【问题标题】:Why can C++ deduce template arguments on the right side of an assignment operator from the left side?为什么 C++ 可以从左侧推导出赋值运算符右侧的模板参数?
【发布时间】:2018-06-04 23:47:32
【问题描述】:
template <typename T>
void func(T&){
}

int main(){
    void (*p)(int&) = func;//or &func
    return 0;
}

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

编辑: 我想出了一个可能的解释。该作业有签名:

void(*&)(int&)operator=(void(*)(int&));

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

【问题讨论】:

  • 请注意,在您发布的第一个 sn-p 中没有赋值运算符。变量初始化中出现的= 不会调用operator =。例如。 C x = 4; 将调用类 C 的构造函数,而不是 C::operator=

标签: c++ templates language-lawyer


【解决方案1】:

这是标准行为吗?

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

模板参数可以从取时指定的类型推导出来 重载函数的地址。函数模板的 函数类型和指定类型作为 P 和 A 的类型, 并且按照[temp.deduct.type]中的描述进行扣除。

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

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

不是真的。一方面,这不是分配,而是您正在做的初始化。即使它使用了重载的operator= 函数,你也需要推导来初始化赋值运算符的参数,这会让你回到第一个问题。

【讨论】:

  • 模组就在那里。等待敲门声。
  • @lowsfer - 很容易。您的示例不进行分配,而是进行初始化。尽管分配的答案也将保持不变。
  • 值得一提的是,这是一种罕见的情况,即 C++ 表达式在使用之前没有特定类型。这是通过特殊情况详细说明的here 允许的。
  • @YSC C++ 中的大多数表达式都有一个类型。重载函数的名称可以作为表达式存在,但在解决重载之前没有类型,这是“从外部”完成的,这是一个有趣的怪癖(以及泛型编程中的 PITA,因为重载集不是第一个——阶级公民)。其他奇怪的表达方式到处隐藏,但不太可能跳到你身上,例如the foo.bar in foo.bar(42);(这是一个prvalue!)。还有初始化列表(语法,而不是对象)。公平地说,这都是无用的怪事:)
  • @StoryTeller:这不是“无用”的最佳含义吗? :)
猜你喜欢
  • 2016-06-08
  • 2023-04-10
  • 2015-06-12
  • 1970-01-01
  • 2023-03-07
  • 2016-11-25
  • 2017-07-16
  • 1970-01-01
  • 2021-03-30
相关资源
最近更新 更多