重载C ++模板函数而不复制代码

时间:2012-10-02 18:15:10

标签: c++

我写了以下函数:

template< class C, typename T, typename U >
void addVarCB(C * _this, const std::string &name, 
    T(C::*getter)(void) const, U(C::*setter)(const T&), const std::string &def);

然后我意识到如果setter将T作为输入,它就不会工作,所以我重载了函数:

template< class C, typename T, typename U >
void addVarCB(C * _this, const std::string &name, 
T(C::*getter)(void) const, U(C::*setter)(T), const std::string &def = "");

现在我意识到如果getter返回

,即使这样也会失败
const T &
T &
const T *
T *
const T // yeah this is dumb but someone on my team wrote code like this...

我注定要在整个地方复制相同的代码吗? 希望至少解决方案仅适用于参考版本?

请注意,该函数将this指针指向一个对象,一个getter和一个setter公共成员函数。 然后,该函数将与GUI连接,允许稍后调用getter和setter。

2 个答案:

答案 0 :(得分:2)

某些模板元编程可以解决您的问题:(以下需要C ++ 11,但使用boost可以实现相同的目标)

#include<string>
#include<type_traits>

template<typename T>
struct BaseType {
    typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
};

struct MyClass{
    int a;
    std::string s;
    const int & getA() const {return a;}
    void setA(int a) {this->a=a;}
    std::string getS() const {return s;}
};


template< class C, typename Tget, typename Tset, typename U, 
    class = typename std::enable_if<
                std::is_same<
                   typename BaseType<Tget>::type, 
                   typename BaseType<Tset>::type>::value,void>::type >
void addVarCB(C * _this, const std::string &name, 
    Tget(C::*getter)(void) const, U(C::*setter)(Tset), const std::string &def = "") {
}

int main() {
    MyClass c;
    addVarCB(&c,std::string("a"),&MyClass::getA,&MyClass::setA,std::string("a"));
    //addVarCB(&c,std::string("a"),&MyClass::getS,&MyClass::setA,std::string("a")); // Compiler error
}

这里我们只是简单地推断get和set类型(TgetTset)。然后,我们剥离这些类型的任何常量或引用,并检查它们是否相同;如果没有,我们会使用enable_if触发专门化失败。

答案 1 :(得分:1)

只需设置GetTypeSetType个独立模板参数,让编译器担心它们是否可以转换。

例如。这样:

template< class C, typename T, typename U >
void addVarCB(C * _this, const std::string &name, 
    T(C::*getter)(void) const, U(C::*setter)(const T&), const std::string &def);

要求setter的参数是对任何getter返回的const引用。但是,这个:

template <typename Class, typename GetResult, typename SetArg, typename SetResult>
void addVarCB(Class *instance, std::string const& name,
              GetResult (Class::*getter)() const,
              SetResult (Class::*setter)(SetArg),
              std::string const &def);

允许setter参数和getter返回类型不同。现在,假设你想将一个传递给另一个,它只会在它们可以转换时编译(或者你可以使用C ++ 11或Boost.TypeTraits is_convertible来明确断言)。


...如果不会工作,那么如果您展示addVarCB内部的内容,或者解释您要实现的目标,可能会有所帮助。