compile-time test whether template class implements something

Feb 13, 2010 at 11:52am
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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.

Maybe there is a solution with the new language constructs auto, decltype and varadic templates?


Ciao, Imi.
Last edited on Feb 13, 2010 at 11:54am
Feb 13, 2010 at 12:52pm
Got already a solution in another post.

For the ones interested: The magic chars are "SFINAE" (http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error). It works by combining function overloading and function templates (http://www.gamedev.net/community/forums/topic.asp?topic_id=562030):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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>*); // choose this, if T::Foo() is present
    template <class X> static float Helper(...);  // for no T::Foo, use this. No compile error.

    static void Bar()
    {
        B2T<sizeof(Helper<T>(0))==sizeof(char), T>::FooOrNot(); // use B2T accordingly to which Helper would be used
    }
};


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


PS: The functions Helper are not implemented as they are never called anyway. They are to test the compiler which function he would have selected.
Feb 13, 2010 at 10:37pm
closed account (1yR4jE8b)
Couldn't you just create a Template Specialization, for the base class type that implements the interface? This seems needlessly complex.
Feb 14, 2010 at 1:15am
imi's solution does not force inheritance of an interface and calling of a virtual function -- thus
it is more loosely coupled.

It is complex only in the sense that templates (and SFINAE for that matter) are extremely powerful
but the language syntax is not rich enough to ask such simple questions of a type as "do you have a method named X" or "do you have a virtual destructor".

The result is often necessarily obtuse syntax to accomplish these simple tasks, but the underlying implementation is not just simple -- it's non-existent: basically nothing imi wrote will generate any code whatsoever above the call to FooOrNot().

I also recall seeing another implementation of the question "are you ostreamable" which was
also obtuse and was the only use I've ever seen of implementing the comma operator.


Feb 15, 2010 at 12:14pm
darkestfright, if you meant inheritance from an abstract base class that has a pure virtual function "Foo", then everything jsmith said applies, although I wouldn't care much about the performance aspects if my application would be the standard-stock-IO-bound-database-application.. ;-)

However, I am in an inner loop of a time-critical function and a virtual call plus the dereferencing of the pointer to the struct would cost me like 10% performance..

If you had the non-virtual solution like this in mind:

1
2
3
4
5
6
7
8
9
10
11
template<class T>
struct ToFooOrNotToFoo
{
    static void Bar() {}
};

template <>
struct ToFooOrNotToFoo<HasFoo>
{
    static void Bar() { HasFoo().Foo(); }
};


Then the problem is, that now ToFooOrNotToFoo has to be aware of "HasFoo", whereas I want a generic library possibility where the library does not know anything about it's (template) arguments.

PS: Another disadvantage of this template thingie is, the error messages are uttermost crap. I'll have a look at Boost::concept libarary. Maybe they get compilers to generate better error messages.
Feb 15, 2010 at 8:02pm
closed account (1yR4jE8b)
While this concept does seem extremely strange to me, I'll admit that I am totally intrigued by it. I've always operated under the assumption that if I'm trying to use a function, and it isn't there..there should be an error, because my program won't work the way I intend it, and if something like this came up I could just specialize it myself. I've also never had to work in a time-critical environment, or environments where non-copy dereferencing is considered an expensive operation.

Thanks for exposing me to this concept, I will definitely look into it in depth in the near future. Stuff like this is why I got into Computer Science in the first place.
Topic archived. No new replies allowed.