Ste*_*mer 14 c++ sfinae template-meta-programming c++11
我已经看到这个问题允许人们检查是否存在成员函数,但我试图找出一个类是否有成员类型.
在下面的示例中,两者都评估为"false",但我想找到一种方法,以便has_bar<foo1>::value计算为false,并has_bar<foo2>::value计算为true.
这可能吗?
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T>
class has_bar
{
typedef char yes;
typedef long no;
template <typename C> static yes check( decltype(&C::bar) ) ;
template <typename C> static no check(...);
public:
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
int main()
{
std::cout << has_bar<foo1>::value << std::endl;
std::cout << has_bar<foo2>::value << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑:实施专业化以回应以下答案:
...如果在目标模板中使用C :: bar,则对于没有嵌套类型的类型,模板将自动被丢弃.
我试过这样做,但显然遗漏了一些东西
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T, typename U = void>
struct target
{
target()
{
std::cout << "default target" << std::endl;
}
};
template<typename T>
struct target<T, typename T::bar>
{
target()
{
std::cout << "specialized target" << std::endl;
}
};
int main()
{
target<foo1>();
target<foo2>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Dir*_*ple 15
试试这个
template<class T>
struct Void {
typedef void type;
};
template<class T, class U = void>
struct has_bar {
enum { value = 0 };
};
template<class T>
struct has_bar<T, typename Void<typename T::bar>::type > {
enum { value = 1 };
};
Run Code Online (Sandbox Code Playgroud)
Dav*_*eas 13
您无法获取指向类型成员的成员的指针:
template <typename C> static yes check( decltype(&C::bar) ) ;
Run Code Online (Sandbox Code Playgroud)
子表达式&C::bar仅在bar非类型成员时才有效C.但你需要检查的是它是否是一种类型.对模板的最小更改可能是:
template <typename C> static yes check( typename C::bar* ) ;
Run Code Online (Sandbox Code Playgroud)
如果bar是嵌套类型C,那么该函数重载将是一个有效的候选者(0将是指向任何C::bar类型的指针),但如果C不包含嵌套,bar那么它将被丢弃,第二个测试将是唯一的候选者.
关于是否需要特征存在一个不同的问题,因为如果C::bar在目标模板中使用,则对于没有该嵌套类型的类型,模板将被自动丢弃.
编辑
我的意思是,在你的方法中,你需要为每个可能的嵌套类型创建一个特征,只是为了生成一个包含或不包含嵌套类型的模板(enable_if).让我们采取不同的方法......首先,我们定义一个通用实用程序来根据条件选择一个类型,这不是这个问题所必需的,更简单template <typename T> void_type { typedef void type; };就足够了,但实用程序模板在其他情况下可能很有用:
// General utility: if_<Condition, Then, Else>::type
// Selects 'Then' or 'Else' type based on the value of
// the 'Condition'
template <bool Condition, typename Then, typename Else = void>
struct if_ {
typedef Then type;
};
template <typename Then, typename Else>
struct if_<false, Then, Else > {
typedef Else type;
};
Run Code Online (Sandbox Code Playgroud)
现在只需要使用SFINAE进行类模板特化:
template <typename T, typename _ = void>
struct target {
// generic implementation
};
template <typename T>
struct target<T, typename if_<false,typename T::bar>::type> {
// specialization for types holding a nested type `T::bar`
};
Run Code Online (Sandbox Code Playgroud)
请注意,与您的方法的主要区别在于使用额外的中间模板(替换将失败 - 并且不是错误)生成void类型(成功时).这就是为什么void_type上面的模板也可以工作的原因:你只需要使用嵌套类型作为模板的参数,并且如果失败了,你就不关心模板的作用,只要评估是嵌套的type(必须void)如果成功的话.
如果不明显(这对我来说不是)为什么你的方法不起作用,请考虑编译器在遇到时需要做什么target<foo2>:第一步是发现有一个名为的模板target,但该模板有两个参数,其中只提供了一个参数.然后它查找基本模板(非专用的模板)并发现第二个参数可以默认为void.从这一点开始,它将考虑您的实例化:( target<foo2,void>在注入默认参数之后).它会尝试匹配最好的专业化.只有为其第二个参数专长是 void将予以考虑.您的模板上面只能使用专门的版本,如果T::bar是void(你可以通过更改测试foo2到:struct foo2 { typedef void bar; }因为你不希望专业化踢只有当嵌套类型是void你所需要的额外的模板,将采取C::bar(因此,如果类型不包含嵌套bar,则会失败,但总是会产生void嵌套类型.
| 归档时间: |
|
| 查看次数: |
6119 次 |
| 最近记录: |