C++ std::enable_if有条件地编译成员函数
我试图通过一个简单的例子来了解如何使用C++ std::enable_if有条件地编译成员函数,c++,templates,g++,c++11,C++,Templates,G++,C++11,我试图通过一个简单的例子来了解如何使用std::enable_if。读过之后,我觉得想出一个简单的例子应该不会太难。我想使用std::enable_if在两个成员函数之间进行选择,并且只允许使用其中一个 不幸的是,下面的代码并没有用GCC4.7编译,经过数小时的尝试,我问你们我的错误是什么 #include <utility> #include <iostream> template< class T > class Y { public:
std::enable_if
。读过之后,我觉得想出一个简单的例子应该不会太难。我想使用std::enable_if
在两个成员函数之间进行选择,并且只允许使用其中一个
不幸的是,下面的代码并没有用GCC4.7编译,经过数小时的尝试,我问你们我的错误是什么
#include <utility>
#include <iostream>
template< class T >
class Y {
public:
template < typename = typename std::enable_if< true >::type >
T foo() {
return 10;
}
template < typename = typename std::enable_if< false >::type >
T foo() {
return 10;
}
};
int main() {
Y< double > y;
std::cout << y.foo() << std::endl;
}
#包括
#包括
模板
Y类{
公众:
模板::type>
T foo(){
返回10;
}
模板::type>
T foo(){
返回10;
}
};
int main(){
YY;
std::coutSFINAE仅当模板参数的参数推导中的替换导致构造格式错误时才起作用。没有这种替换
我也想到了这一点,并尝试使用std::is_same::value
和!std::is_same::value
,得到相同的结果
这是因为当实例化类模板时(在其他情况下,当您创建类型为Y
的对象时会发生这种情况),它会实例化其所有成员声明(不一定是它们的定义/主体!)。其中还有它的成员模板。请注意,T
是已知的,并且!std::is_same::value
产生false。因此它将创建一个包含
class Y<int> {
public:
/* instantiated from
template < typename = typename std::enable_if<
std::is_same< T, int >::value >::type >
T foo() {
return 10;
}
*/
template < typename = typename std::enable_if< true >::type >
int foo();
/* instantiated from
template < typename = typename std::enable_if<
! std::is_same< T, int >::value >::type >
T foo() {
return 10;
}
*/
template < typename = typename std::enable_if< false >::type >
int foo();
};
Y类{
公众:
/*实例化自
模板::value>::type>
T foo(){
返回10;
}
*/
模板::type>
int foo();
/*实例化自
模板::value>::type>
T foo(){
返回10;
}
*/
模板::type>
int foo();
};
std::enable\u if::type
访问一个不存在的类型,因此声明格式不正确。因此,您的程序无效
如果
依赖于成员模板本身的参数,则需要使成员模板的启用。\u。然后声明是有效的,因为整个类型仍然是依赖的。当您尝试调用其中一个时,会对其模板参数进行参数推导,并按预期进行SFINAE。请参阅和相应的答案关于如何做到这一点。解决此问题的一种方法是,成员函数的专门化是将专门化放在另一个类中,然后从该类继承。您可能必须更改继承顺序才能访问所有其他底层数据,但此技术确实有效
template< class T, bool condition> struct FooImpl;
template<class T> struct FooImpl<T, true> {
T foo() { return 10; }
};
template<class T> struct FoolImpl<T,false> {
T foo() { return 5; }
};
template< class T >
class Y : public FooImpl<T, boost::is_integer<T> > // whatever your test is goes here.
{
public:
typedef FooImpl<T, boost::is_integer<T> > inherited;
// you will need to use "inherited::" if you want to name any of the
// members of those inherited classes.
};
templatestruct FooImpl;
模板结构FooImpl{
T foo(){return 10;}
};
模板结构{
T foo(){return 5;}
};
模板
Y类:public FooImpl//无论您的测试是什么,都会在这里进行。
{
公众:
typedef FooImpl继承;
//如果要命名任何
//这些继承类的成员。
};
这种技术的缺点是,如果您需要为不同的成员函数测试很多不同的东西,那么您必须为每个成员函数创建一个类,并将其链接到继承树中。这对于访问公共数据成员是正确的
例:
模板类Goo;
//重复上面的模式。
模板
Foo类:公共Goo{
公众:
typedef-Goo继承:
//等等等等。
};
我做了一个简短的例子,这个例子同样有效
#include <iostream>
#include <type_traits>
class foo;
class bar;
template<class T>
struct is_bar
{
template<class Q = T>
typename std::enable_if<std::is_same<Q, bar>::value, bool>::type check()
{
return true;
}
template<class Q = T>
typename std::enable_if<!std::is_same<Q, bar>::value, bool>::type check()
{
return false;
}
};
int main()
{
is_bar<foo> foo_is_bar;
is_bar<bar> bar_is_bar;
if (!foo_is_bar.check() && bar_is_bar.check())
std::cout << "It works!" << std::endl;
return 0;
}
#包括
#包括
foo类;
分类栏;
模板
结构是
{
模板
typename std::enable_if::type check()
{
返回true;
}
模板
typename std::enable_if::value,bool>::类型检查()
{
返回false;
}
};
int main()
{
is_bar foo_is_bar;
是吧,是吧;
如果(!foo_is_bar.check()&&bar_is_bar.check())
std::cout布尔值需要依赖于推导的模板参数。因此,一种简单的修复方法是使用默认布尔值参数:
template< class T >
class Y {
public:
template < bool EnableBool = true, typename = typename std::enable_if<( std::is_same<T, double>::value && EnableBool )>::type >
T foo() {
return 10;
}
};
您还可以实现您自己的member requires宏,如下所示(以防您不想使用其他库):
模板
结构需要枚举
{
枚举类类型
{
没有一个
全部的
};
};
#定义成员_需要(…)\
typename需要枚举::type PrivateRequestResenum 35;###行_u=需要枚举::类型::无\
class=typename std::enable\u if::type
发帖:
默认模板参数不是模板签名的一部分
但我们可以这样做:
#include <iostream>
struct Foo {
template < class T,
class std::enable_if < !std::is_integral<T>::value, int >::type = 0 >
void f(const T& value)
{
std::cout << "Not int" << std::endl;
}
template<class T,
class std::enable_if<std::is_integral<T>::value, int>::type = 0>
void f(const T& value)
{
std::cout << "Int" << std::endl;
}
};
int main()
{
Foo foo;
foo.f(1);
foo.f(1.1);
// Output:
// Int
// Not int
}
#包括
结构Foo{
模板::type=0>
空f(常数T和值)
{
std::cout对于那些正在寻找“只起作用”的解决方案的后来者:
跑步可以带来:
./a.out
11
下面是我的极简主义示例,使用宏。
使用更复杂的表达式时,请使用双括号启用_if(…)
template<bool b, std::enable_if_t<b, int> = 0>
using helper_enable_if = int;
#define enable_if(value) typename = helper_enable_if<value>
struct Test
{
template<enable_if(false)>
void run();
}
模板
使用helper_enable_if=int;
#定义enable_if(value)typename=helper_enable_if
结构测试
{
模板
无效运行();
}
我不确定,但我认为是这样的:如果基于SFINAE启用(替换失败不是错误)。但是,这里没有任何替换,因为没有参数不能用于确定要使用哪个重载。您应该使“true”和“false”依赖于t。(我知道你不想在这个简单的例子中这样做,但现在可能太简单了…)我也想到了这一点,并尝试使用std::is_sametemplate<long N>
struct requires_enum
{
enum class type
{
none,
all
};
};
#define MEMBER_REQUIRES(...) \
typename requires_enum<__LINE__>::type PrivateRequiresEnum ## __LINE__ = requires_enum<__LINE__>::type::none, \
class=typename std::enable_if<((PrivateRequiresEnum ## __LINE__ == requires_enum<__LINE__>::type::none) && (__VA_ARGS__))>::type
#include <iostream>
struct Foo {
template < class T,
class std::enable_if < !std::is_integral<T>::value, int >::type = 0 >
void f(const T& value)
{
std::cout << "Not int" << std::endl;
}
template<class T,
class std::enable_if<std::is_integral<T>::value, int>::type = 0>
void f(const T& value)
{
std::cout << "Int" << std::endl;
}
};
int main()
{
Foo foo;
foo.f(1);
foo.f(1.1);
// Output:
// Int
// Not int
}
#include <utility>
#include <iostream>
template< typename T >
class Y {
template< bool cond, typename U >
using resolvedType = typename std::enable_if< cond, U >::type;
public:
template< typename U = T >
resolvedType< true, U > foo() {
return 11;
}
template< typename U = T >
resolvedType< false, U > foo() {
return 12;
}
};
int main() {
Y< double > y;
std::cout << y.foo() << std::endl;
}
g++ -std=gnu++14 test.cpp
./a.out
11
template<bool b, std::enable_if_t<b, int> = 0>
using helper_enable_if = int;
#define enable_if(value) typename = helper_enable_if<value>
struct Test
{
template<enable_if(false)>
void run();
}