即使给出了该专业化的类型值,NTTP 构造是否总是发生在 CTAD 中?

问题描述 投票:0回答:1

这(部分)从 CTAD 在给出显式参数时实例化其他专业化减少。

https://godbolt.org/z/5To7nKEP3

template<int N>
struct Bar {
    int n = N;
    constexpr Bar() {}
    constexpr Bar(const Bar& b): n{b.n - 1} {}
};

template<Bar b> constexpr int get_n() { return b.n; }

constexpr auto b = Bar<1>{};
static_assert(b.n == 1);

#ifdef _MSC_VER
static_assert(get_n<b>() == 1);
#else
static_assert(get_n<b>() == 0);
#endif

Clang 和 GCC 似乎总是从

Bar
的构造函数调用和推导来确定 real 模板参数,即使 given 参数是
Bar
的专业化类型,MSVC 不同意这一点.

标准怎么说?

c++ c++20 ctad
1个回答
0
投票

对于任何一个

static_asserts
,程序都应该是格式错误的。

首先请注意,这与 CTAD 无关。如果您显式指定

Bar<1>
作为模板参数类型,您仍然会获得相同的编译器行为。

类模板实参推导始终会完成,并将在此处推导

Bar<1>

但是,问题不在于模板参数对象如何从模板参数初始化以确定将被调用的

get_n
的相关专业化。

对于类类型究竟如何发生这种情况尚未明确,请参阅 CWG 问题 2459

2023 年底通过论文P2308R1解决问题使得

get_n<b>()
的调用格式不正确。

基本上,新规则规定,应用于您的示例,我们首先想象一个定义为的变量

constexpr Bar<1> v = b;

然后我们进一步想象模板参数对象(也是前面推导的

Bar<1>
类型)是从表达式
v
复制初始化的。如果模板参数对象的值不是template-argument-equivalent(即“相同”),则该程序是错误的。

在您的情况下会发生这种情况,因为复制构造函数(在

v
的初始化和模板参数对象的复制初始化中使用)将在新对象中生成与源对象中不同的值。

似乎还没有一个编译器实现了这一点。

© www.soinside.com 2019 - 2024. All rights reserved.