当与decltype一起使用时,函数类型的含义

4

我正在研究decltypestd::is_same_v,并尝试将它们应用于函数。

template<typename T>
void func(T t){}

template<typename T>
using f = decltype(func<T>);

template<typename T>
using ff = decltype((func<T>));

template<typename T>
using fff = void(*)(T);


template<typename T, typename U, typename Z>
void test(T t, U u, Z z){
   std::cout << __PRETTY_FUNCTION__ << std::endl;
   std::cout << std::boolalpha
             << std::is_same_v<T, U> << " "
             << std::is_same_v<U, Z> << " "
             << std::is_same_v<Z, T>;
}
int main()
{
    f<int> f1; // 1
    ff<int> ff1 = func<int>; // 2
    fff<int> fff1 = func<int>;

    test(f1, ff1, fff1);
    return 0;
}

演示链接

输出:

void test(T, U, Z) [with T = void (*)(int); U = void (*)(int); Z = void (*)(int)]
true true true

我在编辑时不小心删除了参数并运行了代码。 演示链接

template<typename T, typename U, typename Z>
void test(T t, U u) // Z z is missing
{ // nothing changed in the body }
no matching function for call to 'test(void (&)(int), void (&)(int), void (*&)(int))'
   36 |     test(f1, ff1, fff1);
      |                       ^

看起来Z是不同的类型,但std::is_same_v<U, Z>返回true。根据cppreference中对decltype的描述,我认为fff应该是不同的类型。

请注意,如果对象的名称被括在括号中,它会被视为普通的左值表达式,因此decltype(x)decltype((x))通常是不同的类型。


  1. 当我尝试初始化f f1 = func<int>;时,我得到一个警告和一个错误。
 warning: declaration of 'void f1(int)' has 'extern' and is initialized
   32 |     f<int> f1 =func<int>;
      |            ^~
<source>:32:16: error: function 'void f1(int)' is initialized like a variable
   32 |     f<int> f1 =func<int>;
      |                ^~~~~~~~~
当我不初始化ff ff1;时,会出现错误提示。
error: 'ff1' declared as reference but not initialized
   33 |     ff<int> ff1 ;
      |             ^~~
据我所知,由于decltype((func<T>)),我得到的是引用类型,但在test中,std::is_same_v返回了true。 显然,std::is_same_v告诉我们这三个都是相同的,但它们实际上是不同的。我是c++的初学者,无法理解发生了什么。

2
你得到的诊断结果显示类型不匹配在值衰减之前。请注意,这些衰减的类型与您编译的第一个示例中的输出匹配。 - Patrick Roberts
@PatrickRoberts 谢谢。从问题 ff 可以看出,f 是一个函数指针(不确定),而 ff 是一个引用类型的函数指针。这是否意味着当传递给函数时,它们总是像数组一样被衰减为指针? - TheScore
2
当传递到test()函数时,既非ff也非f最初是指针类型(尽管fff是),f是值类型,而ff是引用类型,但两者在传递到test()时都会衰减为指针。 - Patrick Roberts
@PatrickRoberts 非常感谢。现在我理解得更清楚了。我应该把 std::is_same_v 放在主函数里。std::is_same_v<void(int), f<int>> -> true...std::is_same_v<void(&)(int), ff<int>> -> true...std::is_same_v<void(*)(int), fff<int>> -> true。希望我所有的类型都是正确的。请考虑添加一个答案。我会接受它。再次感谢您的时间和耐心。 - TheScore
我不理解 f f1 = func<int>; 给出的错误,这是什么意思呢? - TheScore
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2

你的代码与以下代码类似:

f<int> f1;                 // `void f1(int);`, function declaration
ff<int> ff1 = func<int>;   // `void (&ff1)(int) = func<int>;`, reference to function
fff<int> fff1 = func<int>; // `void (*fff1)(int) = &func<int>;` pointer to function,
                           // decay of `func<int>` to pointer
作为C数组,您无法按值传递函数;它们会衰变为指针。 因此,
test(f1, ff1, fff1); // test(&f1, &ff1, fff1);

在测试内部,所有参数的类型都是 void (*)(int)


谢谢。这个警告信息是什么意思?void f1(int)的声明有'extern'并且被初始化了。 - TheScore
1
你不能初始化一个函数 int f1(int) = /*..*/; - Jarod42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,