我发现以下一段代码:
#include <iostream>
#include <vector>
template <typename T>
struct X : std::false_type {};
template <template <typename> class Y, typename U>
struct X<Y<U>> : std::true_type {};
int main() {
if (X<int>())
std::cout << "wrong\n";
if (X<std::vector<double>>())
std::cout << "correct\n";
return 0;
}
仅在correct
与g++-7
一起编译时才打印-std=c++1z
。其他版本的g++
,clang++
或其他std
标记无法生成正确的内容。
这是当前实现的错误,并且此代码不应该打印任何内容,或者是否在C ++ 17中发生了变化,这使得此代码按预期工作?
答案 0 :(得分:10)
这是在C ++ 17中采用P0522的结果,其动机来自以下示例:
template <template <int> class> void FI(); template <template <auto> class> void FA(); template <auto> struct SA { /* ... */ }; template <int> struct SI { /* ... */ }; FI<SA>(); // OK; error before this paper FA<SI>(); // error template <template <typename> class> void FD(); template <typename, typename = int> struct SD { /* ... */ }; FD<SD>(); // OK; error before this paper (CWG 150)
以前,[temp.arg.template]中的措辞要求模板模板参数完全匹配。所以给出:
template <template <class > class P> class X;
template <class T> class A;
template <class T, class U=T> class B;
template <class... > class C;
X<A>
显然没问题,但是X<B>
格式不正确,因为B
需要两个模板参数(无论是否有一个默认!)而且X<C>
格式不正确因为P
需要一个模板参数而C
需要一个包(即使您只能使用一个参数形成C
!)
如果模板模板参数至少与参数一样专用,那么新措辞就会放松匹配的想法。这使X<B>
和X<C>
都有效。
因此,在C ++ 17中,X<std::vector<double>>
应该选择专门化。但在C ++ 17之前,它应该选择主要的。 gcc正在做正确的事。