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* o开发者_C百科bj1, T2* obj2){
obj1->GetPositionY;
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.
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
}
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.
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.
精彩评论