Griffin
Griffin

Reputation: 2517

How to specify possible data types for a template function

I'm trying to make a function that takes two data types, each of which I know will be a descendent of a drawable class, meaning my function depends on some of drawable's functions. However because it is a template function I can't do this.

How can I make it so I can use these descendant class functions? Or make it so only descendents of drawable are accepted?

here's the beginning of my function. GetPositionY is drawable's function.

template<typename T, typename T2>
bool CheckCollision(T* obj1, T2* obj2){
    obj1->GetPositionY;

Upvotes: 2

Views: 2502

Answers (4)

Jason
Jason

Reputation: 32490

Add a trait structure for your drawable class that you can use to test whether the types instantiated in the template are the correct types. This would look something like

//default for any data-type
template<typename T>
struct drawable_type
{
    enum { drawable = 0 };
};

//specialization for a drawable class
template<>
struct drawable_type<drawable>
{
    enum { drawable = 1 };
};

template<typename T, typename T2>
bool CheckCollision(T* obj1, T2* obj2) 
{ 
    if (drawable_type<T>::drawable && drawable_type<T2>::drawable)
    {
        //do something
    }
    else
        return false; 
}

Now if the types past aren't drawable, your function will simply return false, otherwise you can continue to test and see if a collision occurred.

Upvotes: 0

ribram
ribram

Reputation: 2450

Unlike C#, which will assume the lowest common denominator and requires the use of the "where" clause to resolve this, C++ takes the path of not checking the template type usage until the method is actually invoked with a specific type. So only types that provide the required methods will compile. e.g.

template<typename T, typename T2>
bool CheckCollision(T* obj1, T2* obj2) {
        obj1->GetPositionY;
}

class A
{
        public:
                int GetPositionY;
                A() { };
};

class B
{
        public:
                B() { };
};

int main(int argc, char* argv[])
{
        A a;
        B b;

        // this compiles just fine
        CheckCollision(&a, &a);
        // this line will not compile, "error: 'class B' has no member named 'GetPositionY'"
        // CheckCollision(&b, &b);

        return 0;
}

There is a discussion about this difference with C# and C++ generics here.

Upvotes: 2

Karl von Moor
Karl von Moor

Reputation: 8614

A CheckCollision() function shall require the client to pass an object that provides GetPosition() methods. That's what you do when calling obj1->GetPositionX() inside your template. There's no reason to force it to pass a drawable object.

Upvotes: 3

Joel Falcou
Joel Falcou

Reputation: 6357

By using a combination of :

boost::is_base_of from Boost.TypeTraits http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/boost_typetraits/reference/is_base_of.html

and boost::enable_if

http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html

template<typename T, typename T2>
typename boost::enable_if< boost::is_base_of< Drawable, T1>, bool>::type 
CheckCollision(T* obj1, T2* obj2)
{
  obj1->GetPositionY(); // ... whatever
}

Upvotes: 2

Related Questions