【问题标题】:Is there a way to get Common/templated functionality with different function names?有没有办法获得具有不同功能名称的通用/模板化功能?
【发布时间】:2013-08-09 20:37:01
【问题描述】:

首先,我不知道该如何命名这个问题,所以我希望它足够好。

本质上,我有一大堆函数,它们具有共同的功能,只是类型不同。听起来像模板是吗?但这里有个问题:每个函数都足够具体,我想给每个函数命名。

例如看下面的代码:

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...

这两个功能几乎相同。它们仅在类型和函数名称上有所不同。我可以将函数模板化,但它们将具有相同的名称。我用宏实现了以下内容,但我不喜欢它会使我的代码变得多么不可读:

#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...
};

我更喜欢宏而不是在类和源代码中一遍又一遍地添加函数,但是有没有办法在以不同方式命名结果函数的同时获得模板化功能所以我不会必须使用宏(或者可能使用更友好的宏)?

谢谢。


编辑:我可能输入了太多背景信息,并且歪曲了我实际询问的内容。本质上,我想知道是否可以在没有宏的情况下以某种方式获得上述宏的功能。我试图使函数名称保持不同,即使它们都具有基本相同的实现。

【问题讨论】:

    标签: c++ templates macros


    【解决方案1】:

    怎么样:

    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);
    }
    

    请注意,您可能还需要模板化 StoreAndPerformRequest()

    【讨论】:

    • StoreAndPerformRequest() 可能对基类指针进行操作并调用虚函数,或者可能有足够的重载来处理所有事情。无论哪种方式,都不一定需要模板化StoreAndPerformRequest()
    • @JerryCoffin:这就是为什么在包装函数中明确给出类型的原因。无论如何,这更像是一种通用方式的建议(具有单独命名的包装器的模板化函数),而不是生产代码。
    • 我相信这是最接近我正在寻找的东西。模板不能重命名方法,我一直在寻找一种方法来从宏中获取通用代码并保持方法命名。谢谢!
    【解决方案2】:

    我不知道你的类型之类的,但这行得通吗?

    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
    

    顺便说一下,模板输入应该可以自动推导出来;我不认为您必须明确声明它们,但在某些情况下我之前错了。

    【讨论】:

    • 我没有看到您的getGeneric 的任何输入,编译器可能从中推断出Req
    • 它可能有效,但我正在寻找我正在调用的具有不同名称的函数。我只在示例中放置了 GetSomething() 函数,但也可以发出 Delete/Post 请求。查看问题编辑。
    【解决方案3】:

    可能最简单的方法是为每个类添加一个data(或类似的)typedef:

    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);
    };
    

    然后你可以编写如下调用代码:

    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);
    }
    

    ...你可以称之为:

    auto bar = Get(some_callback);
    auto baz = Get(another_callback);
    

    如果您无法修改这些类,则必须将 typedef 移到特征类型中,然后从那里使用它们:

    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);
    }
    

    【讨论】:

    • 这并不能解决 OP 需要单独命名的函数而不是单个通用“Get”函数的问题。
    • 是的,不是我想要的。请参阅我的问题编辑。谢谢。
    • @JonathanPotter:是的,也不是。现在,他正在寻找一种可以轻松编写每个函数的东西。这将根据您调用它时传递的参数简单地生成所需的每个函数。
    猜你喜欢
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 2021-06-22
    • 1970-01-01
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 2011-10-24
    相关资源
    最近更新 更多