C++20 NTTP 专业化

C++20 NTTP specialization

尝试编译以下代码时,gcc/clang 和 msvc 之间存在分歧:

struct foo {
};

// primary template
template<auto>
struct nttp {
    static constexpr int specializaion = 0;
};

// specialization
template<foo f>
struct nttp<f> {
    static constexpr int specializaion = 1;
};

int main() {
  // Does not compile with msvc 19.30
  nttp<5> x{};
}

完整示例 here.

Msvc 抱怨没有从 intfoo 的可行转换,这显然是正确的,但据我了解部分模板的规则,这里不应该有任何相关性专业化。

引用 cppreference:

When a class or variable (since C++14) template is instantiated, and there are partial specializations available, the compiler has to decide if the primary template is going to be used or one of its partial specializations.

  1. If only one specialization matches the template arguments, that specialization is used
  2. If more than one specialization matches, partial order rules are used to determine which specialization is more specialized. The most specialized specialization is used, if it is unique (if it is not unique, the program cannot be compiled)
  3. If no specializations match, the primary template is used

我认为在这种情况下 int 没有匹配的专业化,因此应该选择主模板。

有趣的是,这种情况可以通过用一个概念约束专业化中的 auto 来解决:

template<class T>
concept Foo = std::is_same_v<T, foo>;

template<auto>
struct nttp {
    static constexpr int specializaion = 0;
};

template<Foo auto f>
struct nttp<f> {
    static constexpr int specializaion = 2;
};

// compiles with all compilers
static_assert(nttp<5>{}.specializaion == 0);

函数模板也按预期工作:

constexpr int test(auto) {
    return 0;
}

constexpr int test(foo) {
    return 1;
}

// compiles with all compilers
static_assert(test(5) == 0);

长话短说:根据经验和直觉,我会说这是 MSVC 中的错误,但一如既往,这里有可能涉及 UB。所以问题是:clang/gcc 正确,还是 MSVC,甚至全部正确?

这是打开的 MSVC 错误报告:

您的程序是 well-formed 根据 [temp.class.spec.match]/2 and [temp.class.spec.match]/3:

/2 A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list, and the deduced template arguments satisfy the associated constraints of the partial specialization, if any.

/3 If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.

/3 作为 P0127R2 (Declaring non-type template parameters with auto), which re-wrote the previously revised wording from the resolution of CWG1315

的一部分进行了专门更新

(After CWG1315, before P0123R2) /3 Each template-parameter shall appear at least once in the template-id outside a non-deduced context.

这 re-write 是专门为了允许对使用 auto 占位符类型声明的 non-template 参数进行部分特化。