将语法与匿名模板类型混淆

Confusing syntax with anonymous template types?

本文关键字:类型 语法      更新时间:2023-10-16
template <class T, class U> decltype(*(T*)(0) * *(U*)(0)) mul(T x, U y) {
   return x * y;
}

该代码取自Stroustrup的C 11常见问题解答。我了解它的作用,这是乘以不同类型的两个对象。使我感到困惑的是模板参数与函数定义之间的语法。decltype内发生了什么?我认为它正在取消初始化为0的未征用的T指针,并将其乘以以相同方式删除和初始化的未命名的U指针。我是吗?

好吧,如果这是发生了什么,那么使用指针,dereences和额外的括号不是多余的吗?我不能在保持所需效果的同时初始化这样的类型?:

template <class T, class U> decltype(T(0) * U(0)) mul(T x, U y) {
   return x * y;
}

这对我来说看起来要干净很多,在乘以两个数字时具有相同的效果...

mul(4, 3); // 12

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

您的版本是不是等效的。

  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);

但是,它无法利用延迟返回类型规范,该规范是为了允许在 之后推迟返回类型的声明该函数的参数声明: auto f(int, int) -> int。一旦声明了参数,它们就可以使用,这对于decltype

非常有用。
template <typename T, typename U>
auto mul(T x, U y) -> decltype(x * y);

保证后一种形式可以选择相同的运算符超载,而不是功能主体,以重复费用(不幸的是)。

您的代码版本假设t和u具有默认的构造函数。Stroustrup版本没有,它通过取消定位空指针来创建虚拟对象。当然,这并不重要,因为该代码并不是要执行的,它只是要解析以了解所得类型。

decltype内容是未评估的上下文;只要与某种类型产生,那里的情况都没关系。考虑一下T的定义:

struct T
{
    int operator*(const U &) { return 2; }
};

它没有构造函数服用intint可转换为的任何类型;因此,即使在decltype的未评估上下文中,T(0)也不会导致对象。因此,使用未评估的空引用可能是获得正确类型的最简单方法。

底线:您不知道TU有哪些构造函数,因此您应该使用null引用,该引用适用类型的虚拟对象。