如何在C++ 11模板中定义时调用它

phi*_*ipp 2 c++ c++11

看一个像这样的简单模板场景:

class A {
    public:
        int work();
};

class B {
    public:
        int work();
};

class ObjectManager {
    public:
        static void manage( A& obj );
        // manage not defined for class B 
};

template<class T>
doStuff( T t ) {
    t.work();
    ....
    ObjectManager::manage(t);
};


A a;
B b;

doStuf(a);
doStuff(b);
Run Code Online (Sandbox Code Playgroud)

我想知道,实现条件调用的最简洁方法是什么ObjectManager::manage?模板函数应该在编译时确定ObjectManager::manage(T t)是否为给定定义,T并且只在它被激活时激活某些代码行.我想有一些更多嵌套模板调用的解决方案,但对我来说最好只保留一个功能.

T.C*_*.C. 5

请注意,目前您的班级成员都是私人的.它们应该公之于众.

template<class T>
auto call_manage(T* t) -> decltype(ObjectManager::manage(*t)){
    return ObjectManager::manage(*t);
}

void call_manage(...) {}

template<class T>
void doStuff( T t ) {
    t.work();
    //....
    call_manage(std::addressof(t)); // smack whoever overloaded unary 
                                    // operator & in the head first
}
Run Code Online (Sandbox Code Playgroud)

如果表达式ObjectManager::manage(*t)格式正确,则函数模板的替换成功,这总是比匹配更好...,因此调用它.否则,do-nothing过载是唯一可行的功能.

演示.


对于那些喜欢参考的人:

template<class T>
auto call_manage(T& t) -> decltype(ObjectManager::manage(t)){
    return ObjectManager::manage(t);
}

template<class... T>
void call_manage(T&&...) {}

template<class T>
void doStuff( T t ) {
    t.work();
    //....
    call_manage(t);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,单参数重载比函数模板的部分排序规则更可靠于可变参数版本,并且如果两者同样可行,则通过重载决策选择.您也可以接听T&& t和拨打电话manage(std::forward<T>(t)),以便完美转发.

演示.

  • @kec一个简单的`...`传递值,所以1)它将复制和2)传递一个类类型的对象"有一个非平凡的复制构造函数,一个非平凡的移动构造函数,或一个非平凡的析构函数"是"有条件地支持实现定义的语义".因此,如果复制ctor或dtor不是微不足道的,它可能无法编译,即使它编译它也会产生副本. (3认同)