dru*_*rus 3 c++ templates sfinae
我正在尝试禁用具有非std :: string可构造类型的ctor.我的第一次尝试是这样的:
#include <iostream>
struct A
{
template <typename U, typename = typename std::enable_if<std::is_constructible<std::string, U>::value>::type>
A(U&& val)
{
std::cout << "A(std::string&& val)" << std::string(std::forward<U>(val)) << std::endl;
}
template <typename U, typename = typename std::enable_if<not std::is_constructible<std::string, U>::value>::type>
A(U&& val)
{
std::cout << "A(int&& val)" << val << std::endl;
}
};
int main()
{
A a1(1);
A a2("hello");
A a3(std::string("hello"));
}
Run Code Online (Sandbox Code Playgroud)
但编译失败了
A a1(1);
带有以下错误消息:
错误C2535:'A :: A(U &&)':已定义或声明的成员函数(实例).
这意味着,SFINAE的两个条件都成功,并且两个ctors都被使用.
我继续前进并尝试了以下方法:
#include <iostream>
struct A
{
template <typename U>
A(U&& val, typename std::enable_if<std::is_constructible<std::string, U>::value>::type* = nullptr)
{
std::cout << "A(std::string&& val)" << std::string(std::forward<U>(val)) << std::endl;
}
template <typename U>
A(U&& val, typename std::enable_if<not std::is_constructible<std::string, U>::value>::type* = nullptr)
{
std::cout << "A(int&& val)" << val << std::endl;
}
};
int main()
{
A a1(1);
A a2("hello");
A a3(std::string("hello"));
}
Run Code Online (Sandbox Code Playgroud)
幸运的是它编译并且工作正常(实例).
到目前为止,我对第二个解决方案很好,但我真的不明白为什么使用模板化参数启用/禁用ctor的第一种方法不起作用.
条件不是真的,那是不可能的.你可以通过第二种方法的工作得到保证,如果两种方法都是正确的话就不会发生这种情况.
重要的是要记住,默认模板参数不是函数模板签名的一部分.如果我们将两个c'tors减少到他们的签名,我们将得到这个:
template <typename U, typename>
A(U&& val)
{
}
template <typename U, typename>
A(U&& val)
{
}
Run Code Online (Sandbox Code Playgroud)
两者是完全相同的.所以会发生什么是模板参数推导U和尝试进行替换以查看要选择的重载.即使我们无法完成其中一个重载的模板参数推断(最后一个参数总是在其中一个中没有计算),我们仍然会在尝试推导过程时找到两个具有相同签名的模板.所以该计划变得格格不入.
第二种方法有效,因为签名本身取决于enable_if被评估.这就是为什么两个重载中的一个总是会被静默删除的原因,就好像它永远不存在一样.
| 归档时间: |
|
| 查看次数: |
275 次 |
| 最近记录: |