+1  A: 

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; }
Naveen
Because I don't know actually that struct P2 contains big X and P1 contains small x. These structs here just for example. There are could be any stucts or classes.
Kirill V. Lyadvinsky
Naveen
In my question there is the way (actually there are two different ways). But I don't know how to recognize it in both compilers.
Kirill V. Lyadvinsky
A: 

Why don't you just create template specializations of 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?

Magnus Skog
There are more than only two types. Look at my comment to Naveen answer.
Kirill V. Lyadvinsky
+1  A: 

The second answer (litb's) to this shows how to detect a member:

http://stackoverflow.com/questions/257288/possible-for-c-template-to-check-for-a-functions-existence

James Hopkin
Your answer is no applicable to my question because of I don't know type of x(or X) member. It could be int or float or anything else (including user types with defined operations +-*/).
Kirill V. Lyadvinsky
+1  A: 

Try this:

template<class X, bool=&X::x> struct Check_x_t;

template<class P> bool Check_x(P p, Check_x_t<P>* = 0) { return true; }
template<class P> bool Check_x(P p, ...) { return false; }

struct P1 {int x; };
struct P2 {int X; };

void test()
{
  P1 p1; P2 p2;

  Check_x(p1); // returns true
  Check_x(p2); // returns false
}

The following link explains why your first solution is failing on certain compilers:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html

(it fails on Comeau as well as VC).

James Hopkin
+1 brilliant...
Naveen
Kirill V. Lyadvinsky
It compiles on gcc4.3.3. Are you able to upgrade? (My solution has the small advantage of being valid C++ ;-))
James Hopkin
James Hopkin
I can't see that == operation is non-integral. But your solution may be simplified to <pre><code>template<bool> struct helper_check_x;template<class P> bool Check_x(P p, helper_check_x< }template<class P> bool Check_x(P p, helper_check_x< }</code></pre>I'll try to upgrade to gcc4.3.3. Thank you for your answer.
Kirill V. Lyadvinsky
== is non-integral because it is comparing pointer to members. Your neater answer looks good, but doesn't compile on gcc4.3.3 for some reason.
James Hopkin
That 'some reason' is that gcc doesn't allow conversion to bool for non-type template parameters. I don't know if that's correct or not.
James Hopkin
You have to pass a second argument. As it is now, if there *is* a member, the call would be ambiguous. If you pass another argument, overload resolution will figure out that the conversion to "..." will be worse, and call the other function. And, because no boolean conversions happen, a deduction failure always happens, because it would require an invalid conversion of a template argument expression (to bool) - whether or not the member actually exist isn't relevant here.
Johannes Schaub - litb
As I understand it, a function with a ... parameter is always has lower precedence than any other, so it's not ambiguous. But I am concerned about whether the conversion to bool is valid. Gcc accepts it in this form, but not in the similar form suggested by @jia3ep.
James Hopkin
Hmm ... I only compiled it on gcc before (I ran it on VC8). It actually returns false for both :-( Well spotted, @litb :-)
James Hopkin
that's the reason those guys always add a "0" as argument, so that the pointer conversion is preferred over an ellipsis conversion. See 13.3.3.1.3 and 13.3.3.2/2 :) Precedence is based on the cost of argument -> parameter conversion. But if you don't pass any argument, precedence cannot be calculated :)
Johannes Schaub - litb
I don't think that's true: a default argument isn't treated any differently to one you supply.
James Hopkin
Since i found you haven't checked the Standard yet, i wanna quote it from `13.3.2/2`: "If there are m arguments in the list, all candidate functions having exactly m parameters are viable."" A candidate function having more than m parameters is viable only if the (m+1)–st parameter has a default argument (8.3.6).121) For the purposes of overload resolution, the parameter list is truncated on the right, so that there are exactly m parameters."
Johannes Schaub - litb
Thanks - got it now. Trying to compile 'void f(int n=0); void f(...); void test() { f(); }' proves your point pretty quickly!IIUC, the code in my answer should fail to compile due to the first call being ambiguous (and indeed it does on Comeau).
James Hopkin
A: 

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:

http://stackoverflow.com/questions/145814/compile-time-type-based-dispatch

+10  A: 

Another way is this one, which relies on SFINAE for expressions too. If the name lookup results in ambiguity, the compiler will reject the template

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.

Johannes Schaub - litb
At first I did not understand the idea. That is exactly what I needed. This solution works both in MSVC++ 2008 and g++4.2.4.
Kirill V. Lyadvinsky
+1: Got it now!
James Hopkin
@litb: Do you have a link to the Usenet discussion?
James Hopkin
yeah, hold your breath: http://groups.google.com/group/comp.lang.c++.moderated/tree/browse_frm/thread/4f7c7a96f9afbe44/c95a7b4c645e449f?pli=1 (linked from the SO thread you link too by one guy). No worries if you don't get immediately what that guy's code does. It's very clever and took me quite a while too
Johannes Schaub - litb
I can't quite see how is_call_possible discussed there relates to the code in this answer.
James Hopkin
its "has_member" is doing the stuff that my code does too :) it's using that first, because only then "using type::operator();" won't raise a compile error ("operator()" then is guaranteed to exist)
Johannes Schaub - litb
I made my own version of that some time ago: http://codepad.org/eL0Pe1xZ
Johannes Schaub - litb
Got it now, don't know why I missed it on my quick scan through. Codepad.org looks cool :-)
James Hopkin
I added a post on my blog about this, hope you guys don't mind :)at http://cpptalk.wordpress.com/2009/09/11/substitution-failure-is-not-an-error-1/Interesting read.
rmn
I don't mind at all - have fun :)
Johannes Schaub - litb
@rmn, it does *not* check for an `integer` member though, it 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.
Johannes Schaub - litb
@litb, thanks for the correction.
rmn
@litb btw, if we only wanted to know if there's an integer member by the name of x, we could've entirely dropped the whole Fallback part and just have the substitution fail due to not finding that member. Right?
rmn
Johannes Schaub - litb
It would look like http://stackoverflow.com/questions/257288/possible-for-c-template-to-check-for-a-functions-existence/264088#264088 . Note, however, that it has drawbacks: It will fail if the type has inherited the member (because it would need an implicit conversion from `T Base::*` to `T Derived::*`. I haven't yet found a solution for that problem - all "solutions" have their drawbacks, it seems.
Johannes Schaub - litb
now a full explanation of this code is pubished.. at: http://cpptalk.wordpress.com/2009/09/12/substitution-failure-is-not-an-error-2/ litb, you are more than welcome to verify i got it correctly :)
rmn
Sure that's is how the matters are, i think :)
Johannes Schaub - litb
Just saw this, cool stuff. :D Thanks for sharing.
GMan
A: 

Boost.ConceptTraits provides 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:

has_member_##name<T>

This gives true if T has a member type named . Note, however, that this won't detect reference type members.

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.

Vicente Botet Escriba
Concept Traits is no more maintained because while that function evolved into these two ones:http://www.boost.org/doc/libs/1_42_0/libs/mpl/doc/refmanual/introspection.htmlother functions went into Concepts_checks, for instance:http://www.boost.org/doc/libs/1_42_0/libs/concept_check/reference.htm#iterator-archetype
Blaisorblade
You are right. has_xxx is already in Boost and respond to the question. I don't agree for the second link as archetypes and concepts check are the two sides of the same coin.
Vicente Botet Escriba