模板化辅助函数调用具有特定函数

时间:2015-04-22 09:50:51

标签: c++ templates c++11

我确信这可以做到,因为它可以用c宏完成,但不能用语法包围我的脑袋。或者如果它甚至可能。

假设我有B类和C类,都实现了函数foo(int),都继承了A,但是当我调用我的帮助器时我不想知道类型(比如我用enum类型调用,就像这样:

我一直在思考,但无法获得最后的接触:

#include <iostream>
#include <memory>
using namespace std;
struct A {};

template< typename R, typename C, typename... Args > R member_func(R (C::*)(Args...));

template<typename Child_t, typename Child_t::* func, typename ...Args_t>
auto activate(A& parent, Args_t... args) -> decltype(member_func(Child_t::func)) { return static_cast<Child_t&>(parent).*func(forward<Args_t>(args)...); }

template<typename (???)::* func, typename ...Args_t>
auto activate(int type, A& parent, Args_t... args) -> decltype(??? they would both return the same thing) { 
    switch (type) {
        case 0: return activate<B>(parent, forward<Args_t>(args)...);
        case 1: return activate<C>(parent, forward<Args_t>(args)...);
    }
}
struct B : public A { int test(int i) { return i; } };
struct C : public A { int test(int i) { return i+1; } };
void foo() {
    int type = 0;
    A* child = new B;
    cout << activate(type, *child, ??test??, 4) << endl;
}

甚至可能吗? 提示?对问题名称提出建议:)

3 个答案:

答案 0 :(得分:2)

您可以通过函数模板调用具有相同名称的无关类的成员函数:

template<typename O, typename... Args>
auto test(O&& o, Args&&... args)
-> decltype( std::forward<O>(o).test(std::forward<Args>(args)...) )
{
    return std::forward<O>(o).test(std::forward<Args>(args)...);
}

函数模板(如重载集)不能作为参数直接传递给另一个函数。该问题的常见解决方案是将它们包装在函数对象类型中:

struct test_wrapper
{
    template<typename O, typename... Args>
    auto operator()(O&& o, Args&&... args)
    -> decltype( std::forward<O>(o).test(std::forward<Args>(args)...) )
    {
        return std::forward<O>(o).test(std::forward<Args>(args)...);
    }
};

我们的目标是以下列方式编写呼叫:

activate(type, *child, test_wrapper{}, 4)

OP的activate函数模板仍需要确定返回类型。有几个选项,所有选项都有缺点:

  1. 使用第一种情况的返回类型。
  2. 查找所有案例的常见类型。
  3. 从外面提供退货类型。
  4. 由于最后一个可能是最简单的,我现在就用它。通话变为activate<int>(type, *child, test_wrapper{}, 4)

    template<typename Child_t, typename A, typename F, typename ...Args_t>
    auto activate(A& parent, F f, Args_t... args)
    -> decltype( f(static_cast<Child_t&>(parent), std::forward<Args_t>(args)...) )
    { return f(static_cast<Child_t&>(parent), std::forward<Args_t>(args)...); }
    
    template<typename Ret, typename A, typename F, typename ...Args_t>
    Ret activate(int type, A& parent, F f, Args_t... args) { 
        switch (type) {
            case 0: return activate<B>(parent, f, std::forward<Args_t>(args)...);
            case 1: return activate<C>(parent, f, std::forward<Args_t>(args)...);
        }
    }
    

    Live demo

答案 1 :(得分:0)

这是不可能的,因为activate重载int type只传递一个成员函数指针,但需要转发到另一个activate重载与另一个成员每种支持类型的函数指针(即&B::test&C::test)。

答案 2 :(得分:0)

编译方法activate(忘记一秒的返回类型)将不起作用,因为只有一个切换选项调用正确的激活重载,而所有其他选项包含{{1对于return static_cast<X&>(parent)A *child = new Y;不同的任何语句Y无效。

以下是我理解你要做的事情;你有一堆课程,说X ... B1来自一个班级Bn。所有A都实现了一个方法Bi,其中所有T foo( ... )的输出和输入都相同,但i没有实现此方法。您希望以通用方式为A存储Bi,因此您自然会编写i,但之后您想知道如何调用适当的方法A *child = new Bi

有几种方法可以做到这一点。由于方法foo始终具有相同的原型,最简单的方法可能是在foo中将foo声明为虚拟或纯虚拟。

如果您不想使用虚拟,那么您可以使用类似

的内容
A
您可以在函数template <class T, class... Args> typename std::result_of< decltype( &T::foo( Args... ) )(T) >::type call_foo( T& X, Args... args ) { return X.foo( std::forward<Args>(args)... ); } 中使用的