Reputation: 432
First of all, I wasn't sure what to name the question, so I hope it's good enough.
Essentially, I have a whole bunch of functions that have common functionality that only differ by types. Sounds like templates yeah? But here is the catch: Each function is specific enough that I would like to name each function differently.
For example, look at the following code:
bool GetFriendsList(FriendsListRequestData::CallbackType Callback)
{
check(Callback != nullptr);
FriendsListRequest* Request = new FriendsListRequest(this, GetNewRequestID());
FriendsListRequestData* Data = new FriendsListRequestData(Request, Callback);
return StoreAndPerformRequest(Data);
}
bool GetAccountInfo(AccountInfoRequestData::CallbackType Callback)
{
check(Callback != nullptr);
AccountInfoRequest* Request = new AccountInfoRequest(this, GetNewRequestID());
AccountInfoRequestData* Data = new AccountInfoRequestData(Request, Callback);
return StoreAndPerformRequest(Data);
}
// Many more routines...
The two functions are nearly identical. They differ only by types and function names. I could templatize the functions, but they would have the same name. I implemented the following with macros, but I don't like how unreadable it would make my code:
#define IMPLEMENT_REQUEST_FUNCTION(Name, RequestType, RequestDataType) \
bool Name(RequestDataType::CallbackType Callback) \
{ \
check(Callback != nullptr); \
RequestType* Request = new RequestType(this, GetNewRequestID()); \
RequestDataType* Data = new RequestDataType(Request, Callback); \
return StoreAndPerformRequest(Data); \
}
class Foo
{
public:
// other stuff...
IMPLEMENT_REQUEST_FUNCTION(GetFriendsList, FriendsListRequest, FriendsListRequestData)
IMPLEMENT_REQUEST_FUNCTION(GetAccountInfo, AccountInfoRequest, AccountInfoRequestData)
// other stuff...
};
I like the macro better than adding the functions over and over in both the class and the source, but is there a way to get templated functionality while naming the resulting functions differently so I wouldn't have to use the macro (or possibly use a more friendly macro)?
Thank you.
EDIT: I may have put too much background information in and skewed what I was actually asking about. Essentially, I'm wondering if I can get the functionality of the above macro somehow without the macro. I'm trying to keep the function names all different even though they all have essentially the same implementation.
Upvotes: 1
Views: 59
Reputation: 37192
What about:
template <typename R, typename D>
bool Get(typename D::CallbackType Callback)
{
check(Callback != nullptr);
R* Request = new R(this, GetNewRequestID());
D* Data = new D(Request, Callback);
return StoreAndPerformRequest(Data);
}
inline bool GetFriendsList(FriendsListRequestData::CallbackType Callback)
{
return Get<FriendsListRequest, FriendsListRequestData>(Callback);
}
inline bool GetAccountInfo(AccountInfoRequestData::CallbackType Callback)
{
return Get<AccountInfoRequest, AccountInfoRequestData>(Callback);
}
Note that you may need to templatize StoreAndPerformRequest()
as well.
Upvotes: 1
Reputation: 490623
Probably the easiest way to do this would be to add a data
(or something similar) typedef to each of your classes:
class FriendsListRequestData {};
class FriendsListRequest {
public:
typedef FriendsListRequestData data;
FriendsListRequest(some_class *s, int);
};
class AccountInfoRequestData{};
class AccountInfoRequest {
public:
typedef AccountInfoRequestData data;
AccountInfoRequest(some_class *s, int);
};
Then you can write the calling code something like:
class Foo {
template <class T>
bool Get(typename T::CallbackType t) {
T *Request = new T(this, GetNewRequestID());
typename T::data *Data = new typename T::data(Request, t);
return StoreAndPerformRequest(Data);
}
...which you'd call something like:
auto bar = Get(some_callback);
auto baz = Get(another_callback);
If you can't modify those classes, you'd have to move the typedefs out to traits types, and use them from there:
template <class T>
struct req_traits {};
template<>
struct req_traits<FriendsListRequestData> {
typedef FriendsListRequest req;
typedef FriendsListRequestData data;
};
template<>
struct req_traits<AccountInfoRequestData> {
typedef AccountInfoRequest req;
typedef AccountInfoRequestData data;
};
template <class T, class traits=req_traits<T> >
bool Get(typename T::CallbackType t) {
typedef typename traits::req req;
typedef typename traits::data data;
req *Request = new req(this, GetNewRequestID());
data *Data = new data(Request, t);
return StoreAndPerformRequest(Data);
}
Upvotes: 0
Reputation: 2534
I don't know your types and such, but will this work?
template<typename Req, typename Data>
bool getGeneric(Data::CallbackType Callback){
if (Callback != nullptr) return false;
Req* request = new T(this, GetNewRequestID()); //what is *this?
Data* data = new Data(request,Callback);
return StoreAndPerformRequest(data);
}
//getGeneric<FriendsListRequest, FriendsListRequestData> == GetFriendsList
//getGeneric<AccountInfoRequest, AccountInfoRequestData> == GetAccountInfo
By the way, the template inputs should be able to be automatically deduced; I don't think you would have to explicitly declare them, but I've been wrong about that before on some occasions.
Upvotes: 0