以下精简代码不适用于最新的clang ++ 5,但被g ++ 7接受:
template<typename Wrapped, typename U>
struct wrapper;
template<typename Wrapped, typename U=int>
struct wrapper
{
wrapper() = default;
// Automatic deduction guide
constexpr explicit wrapper(Wrapped) noexcept {}
};
int main()
{
struct {} dummy;
constexpr auto wrapped = wrapper(dummy);
}
失败并显示以下错误消息:
<source>:18:30: error: no viable constructor or deduction guide for deduction of template arguments of 'wrapper'
constexpr auto wrapped = wrapper(dummy);
^
<source>:12:24: note: candidate template ignored: couldn't infer template argument 'U'
constexpr explicit wrapper(Wrapped) noexcept {}
^
<source>:4:8: note: candidate template ignored: could not match 'wrapper<Wrapped, U>' against '(anonymous struct at <source>:17:5)'
struct wrapper;
^
<source>:9:5: note: candidate function template not viable: requires 0 arguments, but 1 was provided
wrapper() = default;
^
但是,如果我将默认模板参数=int
从类模板定义移动到前向声明,那么一切都很完美(U
按预期推导到int
),就好像只有在创建演绎指南使用的虚构函数模板集时,会考虑前向声明中的默认模板参数。
我试图阅读标准措辞,但对于这个具体案例,我无法从中得到很多。在生成虚构函数模板时,只将前向声明中的默认模板参数作为预期行为,或者这是编译器错误吗?
答案 0 :(得分:7)
这不是标准本身 1 的引用,但我有足够的信心将其视为答案。
根据cppreference,Default template arguments:
声明中出现的默认模板参数和定义的合并方式类似于默认函数参数:
template<typename T1, typename T2 = int> class A; template<typename T1 = int, typename T2> class A; // the above is the same as the following: template<typename T1 = int, typename T2 = int> class A;
但是同一参数不能在同一范围内两次给出默认参数
template<typename T = int> class X; template<typename T = int> class X {}; // error
这意味着一个隐含的规则:模板类型参数可以在模板声明或模板定义中交替使用。
。clang ++ 5的行为绝对是一个错误。
1)由用户Oliv提供:
[temp.param]/10
可以使用的默认 template-arguments 集合是通过合并模板的所有先前声明中的默认参数获得的,其方式与默认函数参数(
[dcl.fct.default]
)相同。 [实施例:template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A;
相当于
template<class T1 = int, class T2 = int> class A;
- 结束示例]