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:
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:
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?
UPD: Structures P1 and P2 here are only for example. There are could be any classes with unknown members.
P.S. Please, do not post C++11 solutions here because they are obvious and not relevant to the question.
I got redirected here from a question which 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
:That's it. And here is how it would be used (live example):
Things can be made even simpler with a couple of macros:
Which could be used this way:
Why don't you just create template specializations of Check_x ?
Heck, when I think of it. If you only have two types, why do you even need templates for this?
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:Check for member function
void x()
:Check for member variable
x
:Check for member class
x
:Check for member union
x
:Check for member enum
x
:Check for any member function
x
regardless of signature:OR
Details and core:
Macros (El Diablo!):
CREATE_MEMBER_CHECK:
CREATE_MEMBER_VAR_CHECK:
CREATE_MEMBER_FUNC_SIG_CHECK:
CREATE_MEMBER_CLASS_CHECK:
CREATE_MEMBER_UNION_CHECK:
CREATE_MEMBER_ENUM_CHECK:
CREATE_MEMBER_FUNC_CHECK:
CREATE_MEMBER_CHECKS:
Why don't you use specialization like this:
The second answer (litb's) to this shows how to detect a member:
Is it possible to write a template to check for a function's existence?
Here is a solution simpler than Johannes Schaub - litb's one. It requires C++11.
Update: A quick example and the explanation on how this works.
For these types:
we have
HasX<A>::value == true
andHasX<B>::value == false
. Let's see why.First recall that
std::false_type
andstd::true_type
have astatic constexpr bool
member namedvalue
which is set tofalse
andtrue
, respectively. Hence, the two templatesHasX
above inherit this member. (The first template fromstd::false_type
and the second one fromstd::true_type
.)Let's start simple and then proceed step by step until we get to the code above.
1) Starting point:
In this case, there's no surprise:
HasX
derives fromstd::false_type
and henceHasX<bool, double>::value == false
andHasX<bool, int>::value == false
.2) Defaulting
U
:Given that
U
defaults toint
,Has<bool>
actually meansHasX<bool, int>
and thus,HasX<bool>::value == HasX<bool, int>::value == false
.3) Adding a specialization:
In general, thanks to the primary template,
HasX<T, U>
derives fromstd::false_type
. However, there exists a specialization forU = int
which derives fromstd::true_type
. Therefore,HasX<bool, double>::value == false
butHasX<bool, int>::value == true
.Thanks to the default for
U
,HasX<bool>::value == HasX<bool, int>::value == true
.4)
decltype
and a fancy way to sayint
: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 typeint
thus,decltype(0)
meansint
. Analogously,1.2
has typedouble
and thus,decltype(1.2)
meansdouble
.Consider a function with this declaration:
where
foo
is some class type. Iff
is an object of typefoo
, thendecltype(func(f, 0))
meanschar
(the type returned byfunc(f, 0)
).Now, the expression
(1.2, 0)
uses the (built-in) comma operator which evaluates the two sub-expressions in order (that is, first1.2
and then0
), discards the first value and results in the second one. Hence,is equivalent to
Putting this together with
decltype
gives thatdecltype(1.2, 0)
meansint
. There's nothing really special about1.2
ordouble
here. For instance,true
has typebool
anddecltype(true, 0)
meansint
as well.What about a class type? For instace, what does
decltype(f, 0)
mean? It's natural to expect that this still meansint
but it might not be the case. Indeed, there might be an overload for the comma operator similar to the functionfunc
above that takes afoo
and anint
and returns achar
. In this case,decltype(foo, 0)
ischar
.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 tovoid
. Therefore,decltype((void) f, 0)
meansint
. Indeed,(void) f
castsf
fromfoo
tovoid
which basically does nothing but saying that the expression must be considered as having typevoid
. Then the built-in operator comma is used and((void) f, 0)
results in0
which has typeint
. Hence,decltype((void) f, 0)
meansint
.Is this cast really necessary? Well, if there's no overload for the comma operator taking
foo
andint
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 andf
has typeV
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.Bottom line:
decltype((void) f, 0)
is a fancy way to sayint
.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:
Here, again,
decltype((void) T::x, 0)
is a fancy way to sayint
but with the benefit of SFINAE.When
T
is substituted with a type, an invalid construct might appear. For instance,bool::x
is not valid C++, so substitutingT
withbool
inT::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 actuallyHasX<bool, int>
. The specialization forU = int
should be selected but, while instantiating it, the compiler findsbool::x
and ignores the template specialization altogether as if it didn't exist.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
.The same argument used for
bool
holds forB
sinceB::x
is an invalid construct (B
has no memberx
). However,A::x
is OK and the compiler sees no issue in instantiating the specialization forU = int
(or, more precisely, forU = decltype((void) A::x, 0)
). Hence,HasX<A>::value == true
.6) Unnaming
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.