为什么C++可以从左侧推导出赋值运算符右侧的模板参数?

low*_*fer 32 c++ templates language-lawyer

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

int main(){
    void (*p)(int&) = func;//or &func
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我想知道为什么这个代码编译(使用g ++).似乎模板函数的论证是从p的类型推导出来的?这是标准行为吗?

编辑:我想出了一个可能的解释.签名有签名:

void(*&)(int&)operator=(void(*)(int&));
Run Code Online (Sandbox Code Playgroud)

所以func实际上是从operator =的输入参数类型推导出来的,而不是直接从p的类型推导出来的.那是对的吗?

Sto*_*ica 29

这是标准行为吗?

是的.当您获取函数模板的地址时(例如,在分配或初始化函数指针时执行),也会发生模板参数推导.它在[temp.deduct.funcaddr]/1中明确允许:

在获取重载函数的地址时,可以从指定的类型推导出模板参数.函数模板的函数类型和指定的类型用作P和A的类型,并且如[temp.deduct.type]中所述完成演绎.

函数指针类型提供参数(A在上一段中).

所以func实际上是从operator =的输入参数类型推导出来的,而不是直接从p的类型推导出来的.那是对的吗?

并不是的.首先,它不是赋值,它是你正在进行的初始化.即使它使用了重载operator=函数,你也需要推导来初始化赋值运算符的参数,这会使你回到原点.

  • 值得一提的是,这是一种罕见的情况,其中C++表达式在使用之前没有特定的类型.这是特殊套管详细[这里](http://en.cppreference.com/w/cpp/language/overloaded_address)允许的. (6认同)
  • @StoryTeller:那不是"没用"的最佳意思吗?:) (4认同)
  • @lowsfer - 很容易.您的示例不执行赋值,它会进行初始化.虽然答案对于作业来说仍然是一样的. (3认同)
  • @YSC C++中的大多数表达式都有一个类型.重载函数的名称可以作为表达式存在,但在解决重载之前没有类型,这是"从外部"完成的,这是一个有趣的怪癖(和泛型编程中的PITA,因为重载集不是第一个 - 公民).其他怪异的表达式隐藏在这里和那里,但不太可能跳到你身边,例如``foo.bar(42);`中的`foo.bar`(http://eel.is/c++draft /expr.ref#4.3.2)(这是一个prvalue!).还有初始化列表(语法,而不是对象).公平地说,这些都是无用的怪事:) (2认同)