C++ SFINAE:is_constructible for const char[] vs std::string
C++ SFINAE : is_constructible for const char[] vs std::string
我正在尝试禁用具有非 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"));
}
但是在第
行编译失败
A a1(1);
出现以下错误消息:
error C2535: 'A::A(U &&)': member function already defined or declared (live example).
这意味着,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"));
}
幸运的是它可以编译并且工作正常 (live example)。
到目前为止,我对第二种解决方案非常满意,但我真的不明白为什么使用模板参数的 enabling/disabling ctor 的第一种方法不起作用。
两个条件都不成立,那是不可能的。您可以放心,第二种方法有效,如果两者都成立,则不会发生这种情况。
重要的是要记住,默认模板参数不是函数模板签名的一部分。如果我们稍微减少两个 c'tors 到他们的签名,我们会得到这个:
template <typename U, typename>
A(U&& val)
{
}
template <typename U, typename>
A(U&& val)
{
}
而且两者是一模一样的。所以发生的是 U
的模板参数推导和尝试进行替换以查看选择哪个重载。即使我们无法完成其中一个重载的模板参数推导(最后一个参数在其中一个中总是下落不明),但在尝试推导过程时,我们仍然会找到两个具有相同签名的模板。所以程序变成病式了。
第二种方法可行,因为签名本身取决于正在评估的 enable_if
。这就是为什么两个重载之一将始终被静默删除,就好像它从未存在过一样。
我正在尝试禁用具有非 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"));
}
但是在第
行编译失败A a1(1);
出现以下错误消息:
error C2535: 'A::A(U &&)': member function already defined or declared (live example).
这意味着,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"));
}
幸运的是它可以编译并且工作正常 (live example)。
到目前为止,我对第二种解决方案非常满意,但我真的不明白为什么使用模板参数的 enabling/disabling ctor 的第一种方法不起作用。
两个条件都不成立,那是不可能的。您可以放心,第二种方法有效,如果两者都成立,则不会发生这种情况。
重要的是要记住,默认模板参数不是函数模板签名的一部分。如果我们稍微减少两个 c'tors 到他们的签名,我们会得到这个:
template <typename U, typename>
A(U&& val)
{
}
template <typename U, typename>
A(U&& val)
{
}
而且两者是一模一样的。所以发生的是 U
的模板参数推导和尝试进行替换以查看选择哪个重载。即使我们无法完成其中一个重载的模板参数推导(最后一个参数在其中一个中总是下落不明),但在尝试推导过程时,我们仍然会找到两个具有相同签名的模板。所以程序变成病式了。
第二种方法可行,因为签名本身取决于正在评估的 enable_if
。这就是为什么两个重载之一将始终被静默删除,就好像它从未存在过一样。