为什么下面的类模板在 Visual Studio 2019 中编译,而在 gcc 8.3 中没有?

Fal*_* We 6 c++ gcc templates visual-studio

为什么下面的代码可以在 Visual Studio 2019 中编译,而不能在 gcc 8.3 中编译?

#include<array>
template<typename T> class myClass {
public:
template<unsigned int N> myClass(const std::array<T, N>& elems) { /* do something */ }
};

int main() {
    std::array<int, 10> A;
    myClass<int> Tabular(A);
}
Run Code Online (Sandbox Code Playgroud)

这是我从我学生的项目中提取的片段,因为对我来说它看起来很奇怪。我用 gcc 8.3 尝试这个,因为我怀疑编译器抱怨模板参数推导失败。所以我告诉我的学生这行不通。但是他认为这确实可以在 VS 中编译而没有警告,我查了一下,他是对的。

因为我离称自己为专家还很远,所以我无法向自己和我的学生解释是否/为什么/出了什么问题。

son*_*yao 5

Gcc 和 MSVC 都是正确的。的第二个模板参数的std::array类型定义为std::size_t,如何std::size_t定义取决于实现。

typedef /*implementation-defined*/ size_t;
Run Code Online (Sandbox Code Playgroud)

std::size_t是 sizeof 运算符结果的无符号整数类型as well as the sizeof... operator and the alignof operator (since C++11)

的位宽std::size_t不小于 16。(C++11 起)

那么whenstd::size_t定义为和unsigned int代码一样编译就好了,否则会失败;类型不匹配导致非类型模板参数推导失败。

更改unsigned intstd::size_tthen 代码保证可以用任何像样的编译器很好地编译。例如

template<typename T> class myClass {
public:
template<std::size_t N> myClass(const std::array<T, N>& elems) { /* do something */ }
};
Run Code Online (Sandbox Code Playgroud)

以及为什么类型不匹配导致非类型模板参数推导失败。

(强调我的)

如果在形参列表中使用了非类型模板形参,并推导出了相应的模板形参,则所推导出的模板形参的类型(在其封闭的模板形参列表中指定,意味着保留引用)必须匹配非类型模板参数完全,除了 cv 限定符被删除,除了模板参数是从数组中推导出来的——在这种情况下,任何整数类型都是允许的,即使 bool 总是会变为真:

template<int i> class A { };
template<short s> void f(A<s>); // the type of the non-type template param is short

void k1()
{
    A<1> a;  // the type of the non-type template param of a is int
    f(a);    // P = A<(short)s>, A = A<(int)1>
             // error: deduced non-type template argument does not have the same
             // type as its corresponding template argument
    f<1>(a); // OK: the template argument is not deduced, 
             // this calls f<(short)1>(A<(short)1>)
}

template<int&> struct X;
template<int& R> void k2(X<R>&);
int n;
void g(X<n> &x) {
    k2(x); // P = X<R>, A = X<n>
           // parameter type is int&
           // argument type is int& in struct X's template declaration
           // OK (with CWG 2091): deduces R to refer to n
}
Run Code Online (Sandbox Code Playgroud)