Is it possible to take a type as an argument in a function?
I'm trying to write a function for a database class that is basically just a wrapper around a hash_map of objects (say shap开发者_如何学Ces) indexed by ID numbers that will look up an ID and cast it to the appropriate pointer type.
e.g. I'd like to be able to do something like this:
Circle* shapeToLookup = NULL;
int idNum = 12;
database.lookup(idNum, circleToLookup);
if(circleToLookup != NULL)
{
// Do stuff with the circle.
}
and have the database know the type of its argument. Is there a way to do this without either overloading the function (lookup(int, Circle*)
, lookup(int, Rect*)
, ad nauseum)? Can you declare a function like lookup(int, Shape*)
and have it know which type it's given?
Thanks!
template <T>
Database::lookup(int idNum, T TobjectToLookup)
{
// inside here, T is the type of the object passed in/
}
You can do it with a template.
Edit: new implementation based on the extra information. If mymap
is a std::map<int, Shape*>
:
template <typename T>
void lookup(int idNum, T* &ptr) {
auto it = mymap.find(idNum);
if (it == mymap.end()) {
ptr = 0;
} else {
ptr = dynamic_cast<T*>(*it); // Shape must have a virtual member function
}
}
Or you might prefer:
template <typename T>
T* lookup(int idNum) {
auto it = mymap.find(idNum);
if (it == mymap.end()) {
return 0;
}
return dynamic_cast<T*>(*it);
}
Then call it like Circle *circle = database.lookup<Circle>(123);
Obviously polymorphic containers are a whole heap of fun in themselves, but I'll assume you have that sorted. There may well be a shared_ptr
in there somewhere that I've left out.
Old implementation when I thought the DB might store copies of POD:
template <typename T>
void lookup(int idNum, T* &ptr) {
void *theresult = // something based on idNum
// some check needed here that theresult really is the right type.
// how you do this depends on the database, but suppose that
// the database gives us some integer "type" which indicates the type
if (type != type_constant<T>::value) {
ptr = 0;
} else {
ptr = static_cast<T*>(theresult);
}
}
type_constant is an example of "type traits", you implement it like:
template <typename T>
struct type_constant {};
template <>
struct type_constant<Circle> {
static const int value = 1;
};
template <>
struct type_constant<Rectangle> {
static const int value = 2;
};
// etc...
Others have explained how to pass a type to a function (by using function templates). I'd like to give another point of view:
It might be even better to introduce a new virtual function on Shape
and then move the Do stuff with the Circle
part into the reimplementation of that virtual function in the Cricle
class.
That way, you remove the need to know the type. You just fetch a Shape
object from your database and then call a doStuff()
function - and it does the right thing depending on the actual type of the Shape
. A good use case for a virtual function. :-)
Of course, this might be more or less simple, depending on what Do stuff
actually does.
精彩评论