Sign in to follow this  
imi

compile-time test whether template class implements something

Recommended Posts

Hi, is there a way to test at compile time, whether the template parameter type implements some function (without forcing the type to provide a custom constant/typedef?) So that's my problem:
struct HasFoo
{
    void Foo() {}
};

struct NoFoo
{
};

template<class T>
struct ToFooOrNotToFoo
{
    void Bar()
    {
        //if (check_at_compile_time(exists T::Foo))
            T().Foo();
    }
};

void somewhere()
{
    ToFooOrNotToFoo<HasFoo>().Bar();  // calls HasFoo::Foo()
    ToFooOrNotToFoo<NoFoo>().Bar();   // doesn't compile, but should
}
I am looking for the code in the comment ;) (or some equivalent solution). I am aware of the following solution, which forces the template parameter to specify some constant. (Some kind of "least intrusive" solution)
struct HasFoo
{
    static const bool FOO_DEFINED = true;
    void Foo() {}
};

struct NoFoo
{
    static const bool FOO_DEFINED = false;
};

template<class T>
struct ToFooOrNotToFoo
{
	template<bool> struct B2T { static void FooOrNot() {} };
	template<> struct B2T<true> { static void FooOrNot() {T().Foo();} };
	static void Bar()
	{
		B2T<T::FOO_DEFINED>::FooOrNot();
	}
};
I am also aware, that the bool constant can be moved out of the template class into some traits-class. However, I would like a solution where nothing additional has to be done. Just either a function is implemented or not. I already read "Modern C++ Design" and looked at Loki to no avail. Maybe there is a solution with the new language constructs auto, decltype and varadic templates? Ciao, Imi. [Edited by - imi on February 13, 2010 5:20:27 AM]

Share this post


Link to post
Share on other sites
that is what concepts are used for.

unfortunately, since concepts have been kicked out of the c++0x standard, you will have to resort to boost's concept checking library for now. it is not perfect and may seem a little complicated at first, but altogether does a pretty decent job of implementing concept checking with the current c++ featureset.

Share this post


Link to post
Share on other sites
You can do it with SFINAE
struct HasFoo
{
void Foo() {}
};

struct NoFoo
{
};

template <class T>
struct ToFooOrNotToFoo
{
template <bool, class X> struct B2T { static void FooOrNot() {} };
template <class X> struct B2T<true, X> { static void FooOrNot() { X().Foo(); } };

template <void (T::*)()> struct Empty {};
template <class X> static char Helper(Empty<&X::Foo>*);
template <class X> static float Helper(...);

static void Bar()
{
B2T<sizeof(Helper<T>(0))==1, T>::FooOrNot();
}
};


int main()
{
ToFooOrNotToFoo<HasFoo>().Bar();
ToFooOrNotToFoo<NoFoo>().Bar();
}

Share this post


Link to post
Share on other sites
Here is one way of making a trait out of it:


// Fallback, will return char array of size 0
char (*check_for_foo(...))[0];

// Test case, will be only be valid overload for check_for_foo
// if T::Foo is resolved. sizeof(&T::Foo) will be the size of a
// member pointer (e.g. not 0)
//
// Cast is there to make sure Foo has correct parameters/return value
template<class T>
char (*check_for_foo(const T &t))[sizeof(static_cast<void (T::*)()>(&T::Foo))];

template<class T>
struct foo_traits {
// Dummy method to get a T without knowing
// how they are created
static const T & ct();
enum { hasit = sizeof(*check_for_foo(ct())) != 0 };
};


Try google for SFINAE (substitution-failure-is-not-an-error) for better explanations on how this work.


Share this post


Link to post
Share on other sites
Just for the record...

Quote:
Original post by bubu LV

B2T<sizeof(Helper<T>(0))==1, T>::FooOrNot();


This does only work if sizeof(char) == 1 != sizeof(float), right? (Which is practically everywhere :-) )

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
The C standard mandates that sizeof(char) == 1. One might consider using char [2] to represent the "true" case, probably wrapped in a struct.


I usually use a reference-to-array-of-2-chars.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this