[英]Using enable_if to hide member function according to template type
如果模板参数匹配特定类型,我希望我的类模板提供一个额外的函数成员。 我正在尝试使用std::enable_if
来获得 SFINAE 实现,但我正在努力为此找到正确的语法。 我为类似的问题尝试了几种解决方案,但由于某种原因,它们都没有编译。
#include <type_traits>
#include <string>
template < typename T >
class myClass {
public:
using value_type = T;
using other_type = int;
myClass() = default;
virtual ~myClass() = default;
// 'default' member
void function(const value_type& val) {};
// overload #1
// error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template < typename = typename std::enable_if< !std::is_convertible< other_type, value_type >::value >::type >
void function(const other_type& val) {};
// overload #2
// error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template < std::enable_if_t< !std::is_convertible< other_type, value_type >::value >* = nullptr >
void function(const other_type& val) {};
};
int main(int argc, char const *argv[]) {
myClass< std::string > foo; // OK
myClass< float > bar; // error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
return 0;
}
我希望function
可用于所有类型,但它的重载仅在other_type
不能隐式转换为value_type
时才可用。 我将如何实施这个?
在function
成员函数模板重载中, SFINAE 构造 ( std::enable_if_t
) 不包含依赖类型,这意味着没有替换上下文,并且重载的模板头中的失败不是替换失败,它们是硬错误。 记起:
您通常通过添加一个虚拟模板参数来解决这个问题,该参数的默认模板参数是您最初直接使用的封闭类模板的模板参数( T
;您的值类型):
template <typename U = T, typename = typename std::enable_if<
!std::is_convertible<other_type, U>::value>::type>
void function(const other_type &val){};
template <
typename U = T,
std::enable_if_t<!std::is_convertible<other_type, U>::value> * = nullptr>
void function(const other_type &val){};
std::enable_if_t
SFINAE 构造现在依赖于每个成员函数模板重载的上下文。
要应用 SFINAE,您需要尝试使用 SFINAE 的对象拥有自己的模板参数,并且您需要在条件中使用该模板参数。 在这种情况下,你可以通过添加一个模板参数修复typename V = value_type
的模板参数,并使用V
代替value_type
。 现在条件将取决于V
,它是成员函数的模板参数:
#include <type_traits>
#include <string>
template < typename T >
class myClass {
public:
using value_type = T;
using other_type = int;
myClass() = default;
virtual ~myClass() = default;
// 'default' member
void function(const value_type& val) {};
// overload #1
// error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template < typename V = value_type, typename = typename std::enable_if< !std::is_convertible< other_type, V >::value >::type >
// added ^^^^^^^^^^^^^^^^^^^^^^^^ changed value_type to V ^
void function(const other_type& val) {};
// overload #2
// error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template < typename V = value_type, std::enable_if_t< !std::is_convertible< other_type, V >::value >* = nullptr >
// added ^^^^^^^^^^^^^^^^^^^^^^^^ changed value_type to V ^
void function(const other_type& val) {};
};
int main(int argc, char const *argv[]) {
myClass< std::string > foo; // OK
myClass< float > bar; // OK
return 0;
}
由于在 C++20 中引入了概念,大多数 SFINAE 机器都可以简化或至少表达得不那么冗长。
#include <concepts>
#include <iostream>
#include <string>
template < class Type >
class myClass {
public:
myClass() = default;
void function(Type const& val) {
std::cout << "Default: " << val << "\n";
}
template < class Other >
requires (not std::convertible_to<Other, Type>) // <- Constrain
void function(Other const& val) {
std::cout << "Overload: " << val << "\n";
}
};
int main()
{
myClass< std::string > foo;
foo.function("OK"); // Default
foo.function(42); // Overload
myClass< float > bar;
bar.function(42); // Default
bar.function("OK"); // Overload
bar.function(3.14); // Default
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.