为什么声明' void(*pf)(int) = bar; '会触发下面代码片段中的' static_assert

Why does the declaration `void(*pf)(int) = bar;` fires the `static_assert` in the snippet below?

本文关键字:代码 片段 static assert bar void 声明 pf int 为什么      更新时间:2023-10-16

这是我之前问题的延续。注意,声明void (*pf)(int) = bar;触发static_assert。我不明白为什么。还请注意,如果我在此声明中将bar替换为bar<const int>,则代码将编译。

#include <iostream>
#include <type_traits>
template<typename T>
void bar(T t)
{
    static_assert(std::is_same<T, const int>::value, "Error!");
    std::cout << t << 'n';
}
int main()
{
    //  static_assert doesn't fire because T==const int
    bar<const int>(1);
    //  But here static_assert fires because T==int (see the error message). Why is this?
    //  If I replace `bar` by `bar<const int>` below the code compiles.
    void(*pf)(int) = bar;
    pf(1000);
}

生活例子

行为非常简单。从下面的函数指针类型推导出Tint,因此static_assert失败。

void(*pf)(int) = bar; // [T = int]

如果我将bar替换为bar<const int>,代码将编译

这是因为你现在已经明确地指定Tconst int,而不再被推断为int

void(*pf)(int) = bar<const int>; // [T = const int]

你仍然可以创建一个类型为void(*)(int)的函数指针,指向函数void(const int),因为顶级const不是函数签名的一部分。

const添加到函数指针类型中没有帮助,因为同样的原因,在推导出T之前,函数参数类型中的顶级const被丢弃,并且导致与第一个示例相同的行为。

void(*pf)(const int) = bar;  // [T = int]

编译器根据提供的函数指针签名推断出T = int。将void(*pf)(int)更改为void(*pf)(const int)并不能解决这个问题,因为cv限定符在类型推导期间被删除(并且,正如dyp在注释中指出的那样,在确定函数的类型时)。§14.8.2.1/3的c++ 11草案("从函数调用中推导模板实参"):

如果p是cv限定类型,则p类型的顶级cv限定符类型推导时忽略

要解决这个问题,显式地指出您想要的类型:

void(*pf)(const int) = bar<const int>;