C++ 如何检测类中是否存在特定的成员变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1005476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect whether there is a specific member variable in class?
提问by Kirill V. Lyadvinsky
For creating algorithm template function I need to know whether x or X (and y or Y) in class that is template argument. It may by useful when using my function for MFC CPoint class or GDI+ PointF class or some others. All of them use different x in them. My solution could be reduces to the following code:
为了创建算法模板函数,我需要知道作为模板参数的类中是 x 还是 X(以及 y 或 Y)。在将我的函数用于 MFC CPoint 类或 GDI+ PointF 类或其他一些类时,它可能很有用。它们都使用不同的 x 。我的解决方案可以简化为以下代码:
template<int> struct TT {typedef int type;};
template<class P> bool Check_x(P p, typename TT<sizeof(&P::x)>::type b = 0) { return true; }
template<class P> bool Check_x(P p, typename TT<sizeof(&P::X)>::type b = 0) { return false; }
struct P1 {int x; };
struct P2 {float X; };
// it also could be struct P3 {unknown_type X; };
int main()
{
P1 p1 = {1};
P2 p2 = {1};
Check_x(p1); // must return true
Check_x(p2); // must return false
return 0;
}
But it does not compile in Visual Studio, while compiling in the GNU C++. With Visual Studio I could use the following template:
但是它不能在 Visual Studio 中编译,而在 GNU C++ 中编译。使用 Visual Studio,我可以使用以下模板:
template<class P> bool Check_x(P p, typename TT<&P::x==&P::x>::type b = 0) { return true; }
template<class P> bool Check_x(P p, typename TT<&P::X==&P::X>::type b = 0) { return false; }
But it does not compile in GNU C++. Is there universal solution?
但它不能在 GNU C++ 中编译。有通用的解决方案吗?
UPD: Structures P1 and P2 here are only for example. There are could be any classes with unknown members.
UPD:此处的结构 P1 和 P2 仅作为示例。可能有任何具有未知成员的类。
P.S. Please, do not post C++11 solutions here because they are obvious and not relevant to the question.
PS 请不要在这里发布 C++11 解决方案,因为它们很明显并且与问题无关。
采纳答案by Johannes Schaub - litb
Another way is this one, which relies on SFINAE for expressionstoo. If the name lookup results in ambiguity, the compiler will reject the template
另一种方式是这种方式,它也依赖于SFINAE 的表达式。如果名称查找导致歧义,编译器将拒绝模板
template<typename T> struct HasX {
struct Fallback { int x; }; // introduce member name "x"
struct Derived : T, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
template<typename C> static char (&f(...))[2];
static bool const value = sizeof(f<Derived>(0)) == 2;
};
struct A { int x; };
struct B { int X; };
int main() {
std::cout << HasX<A>::value << std::endl; // 1
std::cout << HasX<B>::value << std::endl; // 0
}
It's based on a brilliant idea of someone on usenet.
它基于 usenet 上某人的绝妙想法。
Note: HasX checks for any data or function member called x, with arbitrary type. The sole purpose of introducing the member name is to have a possible ambiguity for member-name lookup - the type of the member isn't important.
注意:HasX 检查任何名为 x 的数据或函数成员,具有任意类型。引入成员名称的唯一目的是使成员名称查找可能存在歧义——成员的类型并不重要。
回答by Cassio Neri
Here is a solution simpler than Johannes Schaub - litb's one. It requires C++11.
这里是一个解决方案不是简单的约翰内斯·绍布- litb的一个。它需要 C++11。
#include <type_traits>
template <typename T, typename = int>
struct HasX : std::false_type { };
template <typename T>
struct HasX <T, decltype((void) T::x, 0)> : std::true_type { };
Update: A quick example and the explanation on how this works.
更新:一个简单的例子和它是如何工作的解释。
For these types:
对于这些类型:
struct A { int x; };
struct B { int y; };
we have HasX<A>::value == true
and HasX<B>::value == false
. Let's see why.
我们有HasX<A>::value == true
和HasX<B>::value == false
。让我们看看为什么。
First recall that std::false_type
and std::true_type
have a static constexpr bool
member named value
which is set to false
and true
, respectively. Hence, the two templates HasX
above inherit this member. (The first template from std::false_type
and the second one from std::true_type
.)
首先回想一下,std::false_type
并且std::true_type
有一个static constexpr bool
名为的成员,分别value
设置为false
和true
。因此,HasX
上面的两个模板继承了这个成员。(第一个模板来自std::false_type
,第二个模板来自std::true_type
。)
Let's start simple and then proceed step by step until we get to the code above.
让我们从简单开始,然后一步一步地进行,直到我们得到上面的代码。
1) Starting point:
1)起点:
template <typename T, typename U>
struct HasX : std::false_type { };
In this case, there's no surprise: HasX
derives from std::false_type
and hence HasX<bool, double>::value == false
and HasX<bool, int>::value == false
.
在这种情况下,HasX
也就不足为奇了:派生自std::false_type
并且因此HasX<bool, double>::value == false
和HasX<bool, int>::value == false
。
2) Defaulting U
:
2) 违约U
:
// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };
Given that U
defaults to int
, Has<bool>
actually means HasX<bool, int>
and thus, HasX<bool>::value == HasX<bool, int>::value == false
.
鉴于U
默认为int
,Has<bool>
实际上意味着HasX<bool, int>
,因此,HasX<bool>::value == HasX<bool, int>::value == false
。
3) Adding a specialization:
3)增加专业:
// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };
// Specialization for U = int
template <typename T>
struct HasX<T, int> : std::true_type { };
In general, thanks to the primary template, HasX<T, U>
derives from std::false_type
. However, there exists a specialization for U = int
which derives from std::true_type
. Therefore, HasX<bool, double>::value == false
but HasX<bool, int>::value == true
.
一般来说,由于主模板,HasX<T, U>
派生自std::false_type
. 然而,存在一个专业化,U = int
其派生自std::true_type
。因此,HasX<bool, double>::value == false
但是HasX<bool, int>::value == true
。
Thanks to the default for U
, HasX<bool>::value == HasX<bool, int>::value == true
.
多亏了默认U
,HasX<bool>::value == HasX<bool, int>::value == true
。
4) decltype
and a fancy way to say int
:
4)decltype
还有一种奇特的说法int
:
A little digression here but, please, bear with me.
这里有点离题,但请耐心等待。
Basically (this is not entirely correct), decltype(expression)
yields the type of expression. For instance, 0
has type int
thus, decltype(0)
means int
. Analogously, 1.2
has type double
and thus, decltype(1.2)
means double
.
基本上(这并不完全正确),decltype(expression)
产生表达式的类型 。例如,0
具有类型int
因此decltype(0)
意味着int
。类似地,1.2
具有类型double
,因此,decltype(1.2)
意味着double
。
Consider a function with this declaration:
考虑带有此声明的函数:
char func(foo, int);
where foo
is some class type. If f
is an object of type foo
, then decltype(func(f, 0))
means char
(the type returned by func(f, 0)
).
foo
一些类类型在哪里。如果f
是 type 的对象foo
,则decltype(func(f, 0))
表示char
(由 返回的类型func(f, 0)
)。
Now, the expression (1.2, 0)
uses the (built-in) comma operator which evaluates the two sub-expressions in order (that is, first 1.2
and then 0
), discards the first value and results in the second one. Hence,
现在,表达式(1.2, 0)
使用(内置)逗号运算符按顺序计算两个子表达式(即 first1.2
和 then 0
),丢弃第一个值并产生第二个值。因此,
int x = (1.2, 0);
is equivalent to
相当于
int x = 0;
Putting this together with decltype
gives that decltype(1.2, 0)
means int
. There's nothing really special about 1.2
or double
here. For instance, true
has type bool
and decltype(true, 0)
means int
as well.
把它放在一起decltype
就decltype(1.2, 0)
意味着int
。没有什么特别的地方1.2
或double
这里。例如,true
也有类型bool
和decltype(true, 0)
手段int
。
What about a class type? For instace, what does decltype(f, 0)
mean? It's natural to expect that this still means int
but it might not be the case. Indeed, there might be an overload for the comma operator similar to the function func
above that takes a foo
and an int
and returns a char
. In this case, decltype(foo, 0)
is char
.
类类型呢?例如,是什么decltype(f, 0)
意思?很自然地期望这仍然意味着int
但可能并非如此。事实上,逗号运算符可能有一个类似于func
上面的函数的重载,它接受 afoo
和 anint
并返回 a char
。在这种情况下,decltype(foo, 0)
是char
。
How can we avoid the use of a overload for the comma operator? Well, there's no way to overload the comma operator for a void
operand and we can cast anything to void
. Therefore, decltype((void) f, 0)
means int
. Indeed, (void) f
casts f
from foo
to void
which basically does nothing but saying that the expression must be considered as having type void
. Then the built-in operator comma is used and ((void) f, 0)
results in 0
which has type int
. Hence, decltype((void) f, 0)
means int
.
我们如何避免对逗号运算符使用重载?好吧,没有办法为void
操作数重载逗号运算符,我们可以将任何内容转换为void
. 因此,decltype((void) f, 0)
意味着int
。实际上,从to 的(void) f
casts基本上什么都不做,只是说表达式必须被视为具有 type 。然后使用内置的运算符逗号,结果which 具有 type 。因此,意味着。f
foo
void
void
((void) f, 0)
0
int
decltype((void) f, 0)
int
Is this cast really necessary? Well, if there's no overload for the comma operator taking foo
and int
then this isn't necessary. We can always inspect the source code to see if there's such operator or not. However, if this appear in a template and f
has type V
which is a template parameter, then it's no longer clear (or even impossible to know) whether such overload for the comma operator exists or not. To be generic we cast anyway.
这个演员真的有必要吗?好吧,如果逗号运算符没有过载foo
,int
那么这不是必需的。我们可以随时检查源代码,看看是否有这样的运算符。但是,如果它出现在模板中并且f
具有V
作为模板参数的类型,那么就不再清楚(甚至不可能知道)逗号运算符的这种重载是否存在。为了通用,我们无论如何都投了。
Bottom line: decltype((void) f, 0)
is a fancy way to say int
.
底线:decltype((void) f, 0)
是一种奇特的说法int
。
5) SFINAE:
5) SFINAE:
This is a whole science ;-) OK I'm exagerating but it's not very simple either. So I'll keep the explanation to the bare minimum.
这是一门完整的科学;-) 好吧,我有点夸大其词,但这也不是很简单。所以我会尽量减少解释。
SFINAE stands for Substitution Failure is Not An Error. It means that when a template parameter is substituted by a type, an illegal C++ code might appear but, in some circunstances, instead of aborting compilation the compiler simply ignores the offending code as if it wasn't there. Let's see how it applies to our case:
SFINAE 代表替换失败不是错误。这意味着当模板参数被类型替换时,可能会出现非法的 C++ 代码,但在某些情况下,编译器不会中止编译,而是简单地忽略有问题的代码,就好像它不存在一样。让我们看看它如何适用于我们的案例:
// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };
// Specialization for U = int
template <typename T>
struct HasX <T, decltype((void) T::x, 0)> : std::true_type { };
Here, again, decltype((void) T::x, 0)
is a fancy way to say int
but with the benefit of SFINAE.
再一次,这decltype((void) T::x, 0)
是一种奇特的说法,int
但得益于 SFINAE。
When T
is substituted with a type, an invalid construct might appear. For instance, bool::x
is not valid C++, so substituting T
with bool
in T::x
yields an invalid construct. Under the SFINAE principle, the compiler doesn't reject the code, it simply ignores (parts of) it. More precisely, as we have seenHasX<bool>
means actually HasX<bool, int>
. The specialization for U = int
should be selected but, while instantiating it, the compiler finds bool::x
and ignores the template specialization altogether as if it didn't exist.
当T
用类型替换时,可能会出现无效的构造。例如,bool::x
不是有效的 C++,因此T
用bool
in替换会T::x
产生无效的构造。在 SFINAE 原则下,编译器不会拒绝代码,它只是忽略(部分)它。更准确地说,正如我们所见,HasX<bool>
实际上意味着HasX<bool, int>
。U = int
应该选择for 的特化,但是在实例化它时,编译器会发现bool::x
并完全忽略模板特化,就好像它不存在一样。
At this point, the code is essencially the same as in case (2) above where just the primary template exists. Hence, HasX<bool, int>::value == false
.
在这一点上,代码本质上与上面的情况 (2) 相同,其中只存在主模板。因此,HasX<bool, int>::value == false
。
The same argument used for bool
holds for B
since B::x
is an invalid construct (B
has no member x
). However, A::x
is OK and the compiler sees no issue in instantiating the specialization for U = int
(or, more precisely, for U = decltype((void) A::x, 0)
). Hence, HasX<A>::value == true
.
用于bool
保持B
自的相同参数B::x
是一个无效的构造(B
没有成员x
)。但是,A::x
没关系,编译器在实例化 for U = int
(或更准确地说, for U = decltype((void) A::x, 0)
)的特化方面没有问题。因此,HasX<A>::value == true
。
6) Unnaming U
:
6)取消命名U
:
Well, looking at the code in (5) again, we see that the name U
is not used anywhere but in its declaration (typename U
). We can then unname the second template argument and we obtain the code shown at the top of this post.
好吧,再次查看(5)中的代码,我们看到该名称U
没有在任何地方使用,而是在其声明(typename U
)中使用。然后,我们可以取消第二个模板参数的命名,并获得本文顶部显示的代码。
回答by Andy Prowl
I got redirected here from a questionwhich has been closed as a duplicate of this one. I know it's an old thread, but I just wanted to suggest an alternative (simpler?) implementation that works with C++11. Supposing we want to check whether a certain class has a member variable called id
:
我从一个问题被重定向到这里,该问题已作为此问题的副本关闭。我知道这是一个旧线程,但我只是想建议一个适用于 C++11 的替代(更简单?)实现。假设我们要检查某个类是否有一个名为 的成员变量id
:
#include <type_traits>
template<typename T, typename = void>
struct has_id : std::false_type { };
template<typename T>
struct has_id<T, decltype(std::declval<T>().id, void())> : std::true_type { };
That's it. And here is how it would be used (live example):
就是这样。这是它的使用方式(现场示例):
#include <iostream>
using namespace std;
struct X { int id; };
struct Y { int foo; };
int main()
{
cout << boolalpha;
cout << has_id<X>::value << endl;
cout << has_id<Y>::value << endl;
}
Things can be made even simpler with a couple of macros:
使用几个宏可以使事情变得更简单:
#define DEFINE_MEMBER_CHECKER(member) \
template<typename T, typename V = bool> \
struct has_ ## member : false_type { }; \
template<typename T> \
struct has_ ## member<T, \
typename enable_if< \
!is_same<decltype(declval<T>().member), void>::value, \
bool \
>::type \
> : true_type { };
#define HAS_MEMBER(C, member) \
has_ ## member<C>::value
Which could be used this way:
可以这样使用:
using namespace std;
struct X { int id; };
struct Y { int foo; };
DEFINE_MEMBER_CHECKER(foo)
int main()
{
cout << boolalpha;
cout << HAS_MEMBER(X, foo) << endl;
cout << HAS_MEMBER(Y, foo) << endl;
}
回答by Brett Rossier
UPDATE: I've recently done some more with the code I posted in my original answer, so I'm updating this to account for changes/additions.
更新:我最近对我在原始答案中发布的代码做了更多的工作,所以我正在更新它以说明更改/添加。
Here are some usage snippets: *The guts for all this are farther down
以下是一些使用片段: *所有这些的胆量都在更远的地方
Check for member x
in a given class. Could be var, func, class, union, or enum:
检查x
给定类中的成员。可以是 var、func、class、union 或 enum:
CREATE_MEMBER_CHECK(x);
bool has_x = has_member_x<class_to_check_for_x>::value;
Check for member function void x()
:
检查成员函数void x()
:
//Func signature MUST have T as template variable here... simpler this way :\
CREATE_MEMBER_FUNC_SIG_CHECK(x, void (T::*)(), void__x);
bool has_func_sig_void__x = has_member_func_void__x<class_to_check_for_x>::value;
Check for member variable x
:
检查成员变量x
:
CREATE_MEMBER_VAR_CHECK(x);
bool has_var_x = has_member_var_x<class_to_check_for_x>::value;
Check for member class x
:
检查成员类x
:
CREATE_MEMBER_CLASS_CHECK(x);
bool has_class_x = has_member_class_x<class_to_check_for_x>::value;
Check for member union x
:
检查会员工会x
:
CREATE_MEMBER_UNION_CHECK(x);
bool has_union_x = has_member_union_x<class_to_check_for_x>::value;
Check for member enum x
:
检查成员枚举x
:
CREATE_MEMBER_ENUM_CHECK(x);
bool has_enum_x = has_member_enum_x<class_to_check_for_x>::value;
Check for any member function x
regardless of signature:
x
无论签名如何,都检查任何成员函数:
CREATE_MEMBER_CHECK(x);
CREATE_MEMBER_VAR_CHECK(x);
CREATE_MEMBER_CLASS_CHECK(x);
CREATE_MEMBER_UNION_CHECK(x);
CREATE_MEMBER_ENUM_CHECK(x);
CREATE_MEMBER_FUNC_CHECK(x);
bool has_any_func_x = has_member_func_x<class_to_check_for_x>::value;
OR
或者
CREATE_MEMBER_CHECKS(x); //Just stamps out the same macro calls as above.
bool has_any_func_x = has_member_func_x<class_to_check_for_x>::value;
Details and core:
细节和核心:
/*
- Multiple inheritance forces ambiguity of member names.
- SFINAE is used to make aliases to member names.
- Expression SFINAE is used in just one generic has_member that can accept
any alias we pass it.
*/
template <typename... Args> struct ambiguate : public Args... {};
template<typename A, typename = void>
struct got_type : std::false_type {};
template<typename A>
struct got_type<A> : std::true_type {
typedef A type;
};
template<typename T, T>
struct sig_check : std::true_type {};
template<typename Alias, typename AmbiguitySeed>
struct has_member {
template<typename C> static char ((&f(decltype(&C::value))))[1];
template<typename C> static char ((&f(...)))[2];
//Make sure the member name is consistently spelled the same.
static_assert(
(sizeof(f<AmbiguitySeed>(0)) == 1)
, "Member name specified in AmbiguitySeed is different from member name specified in Alias, or wrong Alias/AmbiguitySeed has been specified."
);
static bool const value = sizeof(f<Alias>(0)) == 2;
};
Macros (El Diablo!):
宏(暗黑破坏神!):
CREATE_MEMBER_CHECK:
CREATE_MEMBER_CHECK:
//Check for any member with given name, whether var, func, class, union, enum.
#define CREATE_MEMBER_CHECK(member) \
\
template<typename T, typename = std::true_type> \
struct Alias_##member; \
\
template<typename T> \
struct Alias_##member < \
T, std::integral_constant<bool, got_type<decltype(&T::member)>::value> \
> { static const decltype(&T::member) value; }; \
\
struct AmbiguitySeed_##member { char member; }; \
\
template<typename T> \
struct has_member_##member { \
static const bool value \
= has_member< \
Alias_##member<ambiguate<T, AmbiguitySeed_##member>> \
, Alias_##member<AmbiguitySeed_##member> \
>::value \
; \
}
CREATE_MEMBER_VAR_CHECK:
CREATE_MEMBER_VAR_CHECK:
//Check for member variable with given name.
#define CREATE_MEMBER_VAR_CHECK(var_name) \
\
template<typename T, typename = std::true_type> \
struct has_member_var_##var_name : std::false_type {}; \
\
template<typename T> \
struct has_member_var_##var_name< \
T \
, std::integral_constant< \
bool \
, !std::is_member_function_pointer<decltype(&T::var_name)>::value \
> \
> : std::true_type {}
CREATE_MEMBER_FUNC_SIG_CHECK:
CREATE_MEMBER_FUNC_SIG_CHECK:
//Check for member function with given name AND signature.
#define CREATE_MEMBER_FUNC_SIG_CHECK(func_name, func_sig, templ_postfix) \
\
template<typename T, typename = std::true_type> \
struct has_member_func_##templ_postfix : std::false_type {}; \
\
template<typename T> \
struct has_member_func_##templ_postfix< \
T, std::integral_constant< \
bool \
, sig_check<func_sig, &T::func_name>::value \
> \
> : std::true_type {}
CREATE_MEMBER_CLASS_CHECK:
CREATE_MEMBER_CLASS_CHECK:
//Check for member class with given name.
#define CREATE_MEMBER_CLASS_CHECK(class_name) \
\
template<typename T, typename = std::true_type> \
struct has_member_class_##class_name : std::false_type {}; \
\
template<typename T> \
struct has_member_class_##class_name< \
T \
, std::integral_constant< \
bool \
, std::is_class< \
typename got_type<typename T::class_name>::type \
>::value \
> \
> : std::true_type {}
CREATE_MEMBER_UNION_CHECK:
CREATE_MEMBER_UNION_CHECK:
//Check for member union with given name.
#define CREATE_MEMBER_UNION_CHECK(union_name) \
\
template<typename T, typename = std::true_type> \
struct has_member_union_##union_name : std::false_type {}; \
\
template<typename T> \
struct has_member_union_##union_name< \
T \
, std::integral_constant< \
bool \
, std::is_union< \
typename got_type<typename T::union_name>::type \
>::value \
> \
> : std::true_type {}
CREATE_MEMBER_ENUM_CHECK:
CREATE_MEMBER_ENUM_CHECK:
//Check for member enum with given name.
#define CREATE_MEMBER_ENUM_CHECK(enum_name) \
\
template<typename T, typename = std::true_type> \
struct has_member_enum_##enum_name : std::false_type {}; \
\
template<typename T> \
struct has_member_enum_##enum_name< \
T \
, std::integral_constant< \
bool \
, std::is_enum< \
typename got_type<typename T::enum_name>::type \
>::value \
> \
> : std::true_type {}
CREATE_MEMBER_FUNC_CHECK:
CREATE_MEMBER_FUNC_CHECK:
//Check for function with given name, any signature.
#define CREATE_MEMBER_FUNC_CHECK(func) \
template<typename T> \
struct has_member_func_##func { \
static const bool value \
= has_member_##func<T>::value \
&& !has_member_var_##func<T>::value \
&& !has_member_class_##func<T>::value \
&& !has_member_union_##func<T>::value \
&& !has_member_enum_##func<T>::value \
; \
}
CREATE_MEMBER_CHECKS:
CREATE_MEMBER_CHECKS:
//Create all the checks for one member. Does NOT include func sig checks.
#define CREATE_MEMBER_CHECKS(member) \
CREATE_MEMBER_CHECK(member); \
CREATE_MEMBER_VAR_CHECK(member); \
CREATE_MEMBER_CLASS_CHECK(member); \
CREATE_MEMBER_UNION_CHECK(member); \
CREATE_MEMBER_ENUM_CHECK(member); \
CREATE_MEMBER_FUNC_CHECK(member)
回答by Vicente Botet Escriba
Boost.ConceptTraitsprovides between others some macros to define type traits, as for example BOOST_TT_EXT_DEFINE_HAS_MEMBER(name)
, which defines a type trait of the form:
Boost.ConceptTraits之间提供了一些宏来定义类型特征,例如BOOST_TT_EXT_DEFINE_HAS_MEMBER(name)
,它定义了以下形式的类型特征:
has_member_##name<T>
This gives true if T has a member type named . Note, however, that this won't detect reference type members.
如果 T 具有名为 的成员类型,则为真。但是请注意,这不会检测引用类型成员。
In you case it will be enough to add in a header file
在你的情况下,添加一个头文件就足够了
BOOST_TT_EXT_DEFINE_HAS_MEMBER_TYPE(x)
and check as follows
并检查如下
BOOST_STATIC_ASSERT(has_member_x<P1>::value);
The technique used is the same as the one explained on some of the preceding answers.
使用的技术与前面一些答案中解释的技术相同。
Unfortunately this library is no more maintained. Now that C++0x will not includes concept, this library together with SFINAE is a perfect replacement to work with most of the concepts.
不幸的是,这个库不再维护。现在 C++0x 将不包含概念,这个库与 SFINAE 一起是处理大多数概念的完美替代品。
回答by Naveen
Why don't you use specialization like this:
你为什么不使用这样的专业化:
struct P1 {int x; };
struct P2 {int X; };
template<class P>
bool Check_x(P p) { return true; }
template<>
bool Check_x<P2>(P2 p) { return false; }
回答by ralphtheninja
Why don't you just create template specializations of Check_x ?
为什么不创建 Check_x 的模板专业化?
template<> bool Check_x(P1 p) { return true; }
template<> bool Check_x(P2 p) { return false; }
Heck, when I think of it. If you only have two types, why do you even need templates for this?
哎呀,当我想到它的时候。如果你只有两种类型,为什么你甚至需要模板?
回答by user23167
Are the functions (x, X, y, Y) from an abstract base class, or could they be refactored to be so? If so you can use the SUPERSUBCLASS() macro from Modern C++ Design, along with ideas from the answer to this question:
函数 (x, X, y, Y) 是来自抽象基类,还是可以重构为这样?如果是这样,您可以使用 Modern C++ Design 中的 SUPERSUBCLASS() 宏,以及这个问题的答案中的想法:
回答by Alex
We can get at compile time: 0 - not_member, 1 - is_object, 2 - is_function
for each required class and member - object or function: http://ideone.com/Fjm9u5
我们可以在编译时获得:0 - not_member, 1 - is_object, 2 - is_function
对于每个必需的类和成员 - 对象或函数:http: //ideone.com/Fjm9u5
#include <iostream>
#include <type_traits>
#define IS_MEMBER(T1, M) \
struct { \
struct verystrangename1 { bool M; }; \
template<typename T> struct verystrangename2 : verystrangename1, public T { }; \
\
enum return_t { not_member, is_object, is_function }; \
template<typename T, typename = decltype(verystrangename2<T>::M)> constexpr return_t what_member() { return not_member; } \
template<typename T> typename std::enable_if<std::is_member_object_pointer<decltype(&T::M)>::value, return_t>::type constexpr what_member() { return is_object; } \
template<typename T> typename std::enable_if<std::is_member_function_pointer<decltype(&T::M)>::value, return_t>::type constexpr what_member() { return is_function; } \
constexpr operator return_t() { return what_member<T1>(); } \
}
struct t {
int aaa;
float bbb;
void func() {}
};
// Can't be in function
IS_MEMBER(t, aaa) is_aaa_member_of_t;
IS_MEMBER(t, ccc) is_ccc_member_of_t;
IS_MEMBER(t, func) is_func_member_of_t;
// known at compile time
enum { const_is_aaa_member_of_t = (int)is_aaa_member_of_t };
static constexpr int const_is_func_member_of_t = is_func_member_of_t;
int main() {
std::cout << std::boolalpha << "0 - not_member, 1 - is_object, 2 - is_function \n\n" <<
"is aaa member of t = " << is_aaa_member_of_t << std::endl <<
"is ccc member of t = " << is_ccc_member_of_t << std::endl <<
"is func member of t = " << is_func_member_of_t << std::endl <<
std::endl;
return 0;
}
Result:
结果:
0 - not_member, 1 - is_object, 2 - is_function
is aaa member of t = 1
is ccc member of t = 0
is func member of t = 2
For class/struct:
对于类/结构:
struct t {
int aaa;
float bbb;
void func() {}
};