使用匿名模板类型混淆语法?

0x4*_*2D2 5 c++ c++11

template <class T, class U> decltype(*(T*)(0) * *(U*)(0)) mul(T x, U y) {
   return x * y;
}
Run Code Online (Sandbox Code Playgroud)

这段代码取自Stroustrup的C++ 11 FAQ.我理解它的作用,它是两个不同类型的对象相乘.令我困惑的是模板参数和函数定义之间的语法.里面发生了什么decltype?我认为它取消引用一个T初始化为0的未命名U指针,并将它与一个未命名的指针相乘,并以相同的方式进行解引用和初始化.我对吗?

好吧,如果这是正在发生的事情,那么指针,解引用和额外括号的使用是不是多余的?我不能在保持预期效果的同时初始化这样的类型吗?:

template <class T, class U> decltype(T(0) * U(0)) mul(T x, U y) {
   return x * y;
}
Run Code Online (Sandbox Code Playgroud)

这对我来说看起来更干净,并且当像第一个那样乘以两个数字时它确实具有相同的效果......

mul(4, 3); // 12
Run Code Online (Sandbox Code Playgroud)

那么为什么Stroustrup坚持使用复杂的指针,解引用和初始化语法?当然,这是在他介绍新auto语法之前.但无论如何,我的问题是:上述两种形式的初始化之间有什么区别吗?他在哪里使用指针并立即取消引用它们而不是简单地做我所做的,这是用没有指针或解除引用来初始化类型?任何回应表示赞赏.

Mat*_* M. 6

您的版本相同.

  1. 您的版本假设两者TU可以从构建0.从矩阵中预期这一点显然是错误的,但它们可以成倍增加.
  2. T(0)产生临时(可能绑定T&&),同时*(T*(0))产生对现有对象的引用(即,T&),因此可能选择不同的运算符.

但是,Stroustrup的版本和你的版本最终都没有在实践中使用.在相同级别的编译器实现中,可以使用:

template <typename T, typename U>
decltype(std::declval<T>() * std::declval<U>()) mul(T x, U y);
Run Code Online (Sandbox Code Playgroud)

但是它没有利用Late Return Type规范,它被允许在函数的参数声明之后推迟返回类型的声明:auto f(int, int) -> int.一旦声明了参数,就可以使用它们,这非常有用decltype!

template <typename T, typename U>
auto mul(T x, U y) -> decltype(x * y);
Run Code Online (Sandbox Code Playgroud)

保证后一种形式选择与功能体相同的操作员过载,代价是重复(不幸的是).

  • @David:`std :: declval <T>()`有一个返回类型`T&`,因此表达式`std :: declval <T>()*std :: declval <U>()`被编译器作为`operator*(T&,U&)`形式的调用,它查找`operator*`的声明,它将匹配此表单(可能在一些转换后).值"0"是没用的,因为在**未评估的上下文中**(在c ++中`decltype`或`sizeof`中的表达式的技术名称)只有类型很重要,而且C++是静态类型语言,值是不影响类型. (2认同)

J.N*_*.N. 5

您的代码版本假设T和U具有默认构造函数.Stroustrup版本没有,它通过取消引用空指针来创建一个虚拟对象.当然,这并不重要,因为该代码并不意味着要执行,它只是要解析才能知道结果类型.