Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template which enforces interface

Is it possible to create a template accepting types which implement certain interface? For example, I want to say to template user: you can store anything in my container as long as it implements Init() and Destroy() methods.

Thanks

like image 697
jackhab Avatar asked Oct 11 '09 13:10

jackhab


2 Answers

A limited subset of the (intended, but unfortunately cut) C++0x functionality of concepts is provided by the Boost Concept Check library. You can harness it by creating a concept check class for your required interface.

like image 77
Konrad Rudolph Avatar answered Sep 28 '22 09:09

Konrad Rudolph


Firstly, if you require the existence of Init and Destroy, it means the template code uses them somewhere. This means, their existance is already checked by the compiler, as the template won't compile if the type doesn't have those methods.

However, if you want to check for them, then one way might be to use their addresses in some compile-time context, e.g

template <class T>
class X
{
private:
    template <unsigned N>
    struct Number {};
    Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
};

struct A
{
    bool Init();
    void Destroy();
};

struct B {};

int main()
{
    X<A>();
    X<B>();
}

With Comeau the output is:

"ComeauTest.c", line 7: error: class "B" has no member "Init"
          Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
                            ^
          detected during instantiation of class "X<T> [with T=B]" at line 21

"ComeauTest.c", line 7: error: class "B" has no member "Destroy"
          Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
                                               ^
          detected during instantiation of class "X<T> [with T=B]" at line 21

However, this breaks down if either of the required methods is overloaded, and naturally this still doesn't test whether these methods have a suitable prototype.

E.g perhaps you expect bool Init(int, int). You could use a static_cast to check for exact signature, but again this might place unnecessary restrictions on the type. For example, so what if some class has bool Init(long, long) instead)?

One way or another, this effort seems necessary only to make the error messages more obvious. However, I very much doubt that any message that you'd get otherwise without any concepts checks (a la "no suitable method Init to call with T = X when used here") is that bad.

like image 45
UncleBens Avatar answered Sep 28 '22 10:09

UncleBens