为什么在 ctor 的参数列表中用 `decltype(x)` 替换成员 `x` 的类型会破坏 class 模板参数推导?

Why does replacing the type of the member `x` with `decltype(x)` in a ctor's argument list break class template argument deduction?

我正在尝试编写某种预处理器怪兽来制作简单的 ctors。

这与 g++ -std=c++17 一起编译:

template<typename T>
struct foo{
    T x;
    foo(T _x):x(_x){}
};
auto x=foo(3);

但是怪物很难知道 x 的类型,所以我尝试了这个:

template<typename T>
struct foo{
    T x;
    foo(decltype(x) _x):x(_x){}
};
auto x=foo(3);

失败(class template argument deduction failed)。但无论如何 decltype(x) 只是 T,对吧?那么为什么代码示例不相同?

你写的是一种循环逻辑。可以这样想。

编译器看到 foo(3)foo 命名了一个 class 模板,因此它会尝试执行 class 模板参数推导以找出 foo 中的 T 应该是什么。

CTAD 首先从中提取所有构造函数和构建模板推导指南。您有一个构造函数,因此它的指南必须如下所示:

template<typename T> foo(decltype(foo<T>::x) _x) -> foo<T>;

为了推导出 foo 的模板参数 T,您需要用 T 实例化 foo...。你还没有因为弄清楚T是什么是你首先制作这个演绎指南的原因。

这里的简短回答是因为 C++ 标准是这么说的。 decltype 不能将表达式推导为模板参数。

17.8.2.5 Deducing template arguments from a type [temp.deduct.type]

The non-deduced contexts are:

[...]

— The expression of a decltype-specifier.

您正在使用 C++17。如果你使用 decltype 来隐藏一些怪异的东西,你可能需要使用 C++17 的演绎指南来解决它。