【发布时间】:2015-10-07 16:32:33
【问题描述】:
在回答this question 关于尝试构造一个可变参数转发引用构造函数时,只有在没有其他构造函数有效时才应调用该构造函数。也就是说,如果有一个:
C(const char*, size_t) { } // 1
template <typename... T, ???> C(T&&... ) { } // 2
尽管需要转换,但我们希望 C c1{"abc", 2}; 调用 (1),但 C c2{1, 2, 3}; 调用 (2),因为 (1) 不适用。
我提出了以下解决方案:
template <typename... T,
typename = std::enable_if_t<!std::is_constructible<C, T&&...>::value>
>
C(T&&... ) { }
通过提议,我的意思是,我尝试了它,并惊讶地发现它确实有效。它编译并完成了我对 gcc 和 clang 的期望。但是,我无法解释 为什么 它可以工作,或者即使它实际上 supposed 可以工作,而 gcc 和 clang 都只是特别适应。是吗?为什么?
【问题讨论】:
-
根据我的理解,如果另一个构造函数可用于
C c1{"abc", 2};而不是std::enable_if_t将没有任何价值,因此创建类似template <typename... T, typename = >的东西,SFINAE 不会创建模板化构造函数。 -
重新发表我对您的回答的评论:this modified example 表明默认参数 SFINAE 考虑了
C的 所有 构造函数,即使是那些在构造函数模板之后声明的构造函数。 -
尽管它的价值不大,MSVC 2013 也接受 /W4 下的这种语法,并使用this example 打印与 gcc 和 clang 相同的内容,尽管它确实警告多个默认构造函数,并且智能感知似乎不认为对
Foo::Foo的第三次调用是有效的。 (同样,尽管 VC++ 18 很好用) -
当前的工作草案没有描述默认模板参数何时被实例化(见CWG 2008),所以我真的不知道如何能令人满意地回答这个问题。
-
这不是
is_constructible+ 默认函数/模板参数的唯一问题。参见,例如,LWG 2452。