类模板参数推导和默认模板参数

Mor*_*enn 14 c++ templates language-lawyer template-argument-deduction c++17

以下精简代码不适用于最新的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);
}
Run Code Online (Sandbox Code Playgroud)

它失败并显示以下错误消息:

<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;
    ^
Run Code Online (Sandbox Code Playgroud)

但是,如果我将默认模板参数=int从类模板定义移动到前向声明,一切都可以正常工作(按预期U推导出来int),就好像在创建虚构集时只考虑前向声明中的默认模板参数一样演绎指南使用的功能模板.

我尝试阅读标准的措辞,但对于这个具体案例却无法得到很多.在生成虚构函数模板时,仅将前向声明中的默认模板参数作为预期行为,或者这是编译器错误?

YSC*_*YSC 7

这不是标准本身1的引用,但我有足够的信心将其视为答案.

根据cppreference,在Default模板参数上:

出现在声明和定义中的默认模板参数与默认函数参数类似地合并:

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;
Run Code Online (Sandbox Code Playgroud)

但是同一参数不能在同一范围内两次给出默认参数

template<typename T = int> class X;
template<typename T = int> class X {}; // error
Run Code Online (Sandbox Code Playgroud)

这意味着一个隐式规则:模板类型参数可以在模板声明或模板定义中互换地赋予默认类型.

clang ++ 5的行为绝对是一个bug.


1)用户Oliv提供:

[temp.param]/10

可以使用的默认模板参数集是通过合并模板的所有先前声明中的默认参数获得的,其方式与默认函数参数是([dcl.fct.default])相同.[例如:

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
Run Code Online (Sandbox Code Playgroud)

相当于

template<class T1 = int, class T2 = int> class A;
Run Code Online (Sandbox Code Playgroud)

 - 结束例子]

  • C++标准参考[\ [[temp.param \]/10](https://timsong-cpp.github.io/cppwp/n4659/temp#param-10) (4认同)