template <class T, class U> decltype(*(T*)(0) * *(U*)(0)) mul(T x, U y) {
return x * y;
}
这段代码取自 Stroustrup 的 C++11 FAQ .我明白它的作用,就是将两个不同类型的对象相乘。令我困惑的是模板参数和函数定义之间的语法。 decltype
内部发生了什么?我认为它正在取消引用初始化为 0 的未命名 T
指针,并将其乘以以相同方式取消引用和初始化的未命名 U
指针。我说得对吗?
好吧,如果这是正在发生的事情,那么指针、解引用和额外的括号的使用不是多余的吗?我不能在保持预期效果的同时初始化这样的类型吗?:
template <class T, class U> decltype(T(0) * U(0)) mul(T x, U y) {
return x * y;
}
这对我来说看起来更清晰,而且它确实在将两个数字相乘时具有与第一个相同的效果......
mul(4, 3); // 12
那么为什么 Stroustrup 坚持使用复杂的指针、解引用和初始化语法呢?当然,这是在他引入新的 auto
语法之前。但是无论如何,我的问题是:以上两种形式的类型初始化有什么区别吗?他在哪里使用指针并立即取消引用它们,而不是简单地做我所做的,即在没有指针或取消引用的情况下初始化类型?任何回应表示赞赏。
最佳答案
您的版本不是等效的。
- 您的版本假设
T
和U
都可以从0
构造。从矩阵中期望这一点显然是错误的,但它们可以相乘。 T(0)
产生一个临时的(可能绑定(bind)到T&&
)而*(T*(0))
产生一个引用现有对象(即T&
),因此可能会选择不同的运算符。
但是,Stroustrup 的版本和您的版本最终都没有被用于实践。在同等级别的编译器实现中,可以使用:
template <typename T, typename U>
decltype(std::declval<T>() * std::declval<U>()) mul(T x, U y);
但它未能利用延迟返回类型规范,该规范旨在允许在函数的参数声明之后推迟返回类型的声明:auto f (int, int) -> int
。一旦声明了参数,就可以使用,这对 decltype
非常有用!
template <typename T, typename U>
auto mul(T x, U y) -> decltype(x * y);
后一种形式保证选择与函数体相同的运算符重载,但代价是重复(不幸的是)。
关于c++ - 将语法与匿名模板类型混淆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13322405/