Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell if class contains a certain member function in compile time [duplicate]

Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?

say there are 2 classes:

struct A{ int GetInt(){ return 10; } };
struct B{ int m; };

I want to use object of type A or B in following function

tempate< typename T >
int GetInt( const T & t )
{
   //if it's A, I'll call: return t.GetInt();
   //if its' B, I'll call: return t.m;
}

Now, because there are whole bunch of classes, some contain GetInt(), some don't, I don't want to write specialization for each type, I only want to distinguish them by 'containing GetInt() or not in compile time', how should I do this ?

like image 397
JQ. Avatar asked Oct 18 '10 23:10

JQ.


People also ask

What does const member function qualifier do?

The const qualifier at the end of a member function declaration indicates that the function can be called on objects which are themselves const. const member functions promise not to change the state of any non-mutable data members.

How is the member function of a class accessed?

A member function of a class is a function that has its definition or its prototype within the class definition like any other variable. It operates on any object of the class of which it is a member, and has access to all the members of a class for that object.

What is a const member function in c++?

Declaring a member function with the const keyword specifies that the function is a "read-only" function that doesn't modify the object for which it's called. A constant member function can't modify any non-static data members or call any member functions that aren't constant.


1 Answers

Substitution Failure Is Not An Error, or more compactly, SFINAE

But in your particular case, you don't need SFINAE, virtual members, or anything fancy like that.

You just need an ordinary overloaded function.

int GetInt(A& t) { return t.GetInt(); }
int GetInt(const B& t) { return t.m; }

If there's code that needs to be shared between the different versions, refactor it so that there's a template that calls an overloaded inline function, all type-specific behavior is in the inline function, and all shared behavior is in the template.

For your "I have many many classes" need, SFINAE would look more or less like this:

template<typename T>
int GetInt(const T& t, int (T::*extra)() const = &T::GetInt)
{
    return t.GetInt();
}

template<typename T>
auto GetInt(const T& t) -> decltype(t.m)
{
    return t.m;
}

EDIT: The reality of SFINAE is much uglier, at least until C++0x comes around. In fact it starts looking just as bad as GMan's answer.

struct A{ int GetInt() const { return 10; } };
struct B{ int m; };

template<typename T, int (T::*extra)() const>
struct has_mfunc
{
    typedef int type;
};

template<typename T>
typename has_mfunc<T, &T::GetInt>::type GetInt(const T& t)
{
    return t.GetInt();
}

template<typename T, typename U, U (T::*extra)>
struct has_field
{
    typedef U type;
};

template<typename T>
typename has_field<T, int, &T::m>::type GetInt(const T& t)
{
    return t.m;
}

int main(void)
{
   A a;
   B b;
   b.m = 5;
   return GetInt(a) + GetInt(b);
}
like image 65
Ben Voigt Avatar answered Nov 15 '22 10:11

Ben Voigt