模板模板参数和默认值

Flo*_*oop 11 c++ template-templates variadic-templates c++11 c++17

请考虑以下代码:

template<typename T>
struct A { };

// same as A, but with one extra defaulted parameter
template<typename T, typename F = int>
struct B { };

template<template<typename> typename T>
T<int> build() { return {}; }

int main()
{
    build<A>();  // works in gcc and clang
    build<B>();  // works in gcc, does not work in clang
}
Run Code Online (Sandbox Code Playgroud)

g ++(7.3.0)编译代码就好了,但是,clang ++(5.0.1)会发出以下命令:

example.cpp:14:5: error: no matching function for call to 'build'
    build<B>();  // works in gcc, does not work in clang
    ^~~~~~~~
example.cpp:9:8: note: candidate template ignored: invalid
      explicitly-specified argument for template parameter 'T'
T<int> build() { return {}; }
Run Code Online (Sandbox Code Playgroud)

哪个编译器是对的?


注意: 重要的一点显然是:

template<template<typename> typename T>
Run Code Online (Sandbox Code Playgroud)

因为两个编译器都满意:

template<template<typename...> typename T>
Run Code Online (Sandbox Code Playgroud)

所以问题是在传递模板模板参数时是否应该考虑默认值.

max*_*x66 7

据我所知,从C++ 17开始,你的代码是正确的,之前错了.

根据P0522R0,这是新标准的一部分,我在其中看到一个与您的代码非常相似的示例(请参阅"概述"):

template <template <typename> class> void FD();
template <typename, typename = int> struct SD { /* ... */ };
FD<SD>();  // OK; error before this paper (CWG 150)
Run Code Online (Sandbox Code Playgroud)

根据ccpreference中编译器支持表,g ++支持版本7 中的P0522R0,来自版本4的clang ++.因此,两个编译器都应该支持您的代码.

但是查看本页中的表格,对llvm(clang)5的支持被定义为"部分",并且根据说明,

(12):尽管是缺陷报告的解决方案,但默认情况下在所有语言版本中禁用此功能,并且可以使用Clang 4中的标志-frelaxed-template-template-args显式启用此功能.对标准的更改缺少模板部分排序的相应更改,导致合理且先前有效的代码的模糊错误.预计这个问题很快就会得到纠正.

所以,冒风险,您可以尝试使用旗帜-frelaxed-template-template-args.