class 方法的 SFINAE
SFINAE for class methods
文章 https://www.fluentcpp.com/2018/05/15/make-sfinae-pretty-1-what-value-sfinae-brings-to-code/ and https://www.fluentcpp.com/2018/05/18/make-sfinae-pretty-2-hidden-beauty-sfinae/ 解释了如何将 SFINAE 用于 class 方法。 class 的第一个实现如下:
template<typename T>
class MyClass
{
public:
void f(T const& x);
void f(T&& x);
};
防止使用第二个函数f
如果T
是引用,本文提出如下解决方案:
template<typename T>
class MyClass
{
public:
void f(T const& x){}
template<typename T_ = T, typename = std::enable_if_t<!std::is_reference_v<T_>>>
void f(T&& x){}
};
用std::enable_if
代替方法的return类型不就是easier/cleaner吗?所以 class 看起来像下面这样:
template<typename T>
class MyClass
{
public:
void f(T const& x){}
std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}
};
首先,你的技术不行。 T
是 MyClass
中的固定类型 enable_if_t<false>
格式错误。没有执行替换,所以这不是替换失败,它只是一个格式错误的签名。
您可以通过
在一定程度上修复它
template<class T_=T>
std::enable_if_t<!std::is_reference_v<T_>>> f(T_&& x){}
现在,此技术(使用 return 值)不适用于 (A) 构造函数,以及 (B) 当您想推导 return 类型时。
它还混合了return类型和SFINAE代码;两者没有任何关系
最重要的是,这项技术和您正在复制的原始技术都与 "all templates must have a valid instantiation" 有一些可疑的交互。我仍然不清楚这是否适用于固定模板 class 实例化的每个模板方法;如果是这样,那么您必须确保某些 T_
会使正文有效。
Wouldn't it be easier/cleaner to substitute the return type of the method by enable_if?
我想是个人品味问题。
总之,考虑一下你的例子
std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}
不起作用,因为 SFINAE 在特定方法的模板上工作。因此,同样对于您的示例,您必须使用 T_
(我称之为 U
)模板类型并且条件 std::is_reference
必须计算 U
,而不是 T
template <typename U = T>
std::enable_if_t<!std::is_reference_v<U>> f(T&& x){}
无论如何,这两种解决方案都存在 "hijacking" 风险:您可以绕过说明 U
类型
的测试
myClassObject.template f<void>(aReference);
为避免劫持风险,您还必须强加 T
和 U
是同一类型
template<typename U = T,
typename = std::enable_if_t<
!std::is_reference_v<U>
&& std::is_same_v<U, T>>>
void f(T&& x){}
template <typename U = T>
std::enable_if_t<
!std::is_reference_v<U>
&& std::is_same_v<U, T>> f(T&& x)
{ }
文章 https://www.fluentcpp.com/2018/05/15/make-sfinae-pretty-1-what-value-sfinae-brings-to-code/ and https://www.fluentcpp.com/2018/05/18/make-sfinae-pretty-2-hidden-beauty-sfinae/ 解释了如何将 SFINAE 用于 class 方法。 class 的第一个实现如下:
template<typename T>
class MyClass
{
public:
void f(T const& x);
void f(T&& x);
};
防止使用第二个函数f
如果T
是引用,本文提出如下解决方案:
template<typename T>
class MyClass
{
public:
void f(T const& x){}
template<typename T_ = T, typename = std::enable_if_t<!std::is_reference_v<T_>>>
void f(T&& x){}
};
用std::enable_if
代替方法的return类型不就是easier/cleaner吗?所以 class 看起来像下面这样:
template<typename T>
class MyClass
{
public:
void f(T const& x){}
std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}
};
首先,你的技术不行。 T
是 MyClass
中的固定类型 enable_if_t<false>
格式错误。没有执行替换,所以这不是替换失败,它只是一个格式错误的签名。
您可以通过
在一定程度上修复它template<class T_=T>
std::enable_if_t<!std::is_reference_v<T_>>> f(T_&& x){}
现在,此技术(使用 return 值)不适用于 (A) 构造函数,以及 (B) 当您想推导 return 类型时。
它还混合了return类型和SFINAE代码;两者没有任何关系
最重要的是,这项技术和您正在复制的原始技术都与 "all templates must have a valid instantiation" 有一些可疑的交互。我仍然不清楚这是否适用于固定模板 class 实例化的每个模板方法;如果是这样,那么您必须确保某些 T_
会使正文有效。
Wouldn't it be easier/cleaner to substitute the return type of the method by enable_if?
我想是个人品味问题。
总之,考虑一下你的例子
std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}
不起作用,因为 SFINAE 在特定方法的模板上工作。因此,同样对于您的示例,您必须使用 T_
(我称之为 U
)模板类型并且条件 std::is_reference
必须计算 U
,而不是 T
template <typename U = T>
std::enable_if_t<!std::is_reference_v<U>> f(T&& x){}
无论如何,这两种解决方案都存在 "hijacking" 风险:您可以绕过说明 U
类型
myClassObject.template f<void>(aReference);
为避免劫持风险,您还必须强加 T
和 U
是同一类型
template<typename U = T,
typename = std::enable_if_t<
!std::is_reference_v<U>
&& std::is_same_v<U, T>>>
void f(T&& x){}
template <typename U = T>
std::enable_if_t<
!std::is_reference_v<U>
&& std::is_same_v<U, T>> f(T&& x)
{ }