可变参数模板 - 如何创建存储传递参数的类型

时间:2015-11-05 13:29:35

标签: c++ templates c++11 variadic-templates

所以假设我有一个包含函数对象的类,并且在构造函数调用中我传递了参数,这些参数将在稍后传递给函数对象。类似的东西:

class Binder{
public:
    Binder(functional_object, listOfParameters);
    callFunctionalObject(); // calls functional object with given list of parameters
};

在C ++ 11之前,我无法使用Variadic模板,所以可以这样做:

struct none{};

template <typename T1, typename T2=none, typename T3=none>
class Binder{
public:
    Binder(T1 functionalObject, T2 arg1=none(), T3arg3=none());
    void callFunctionalObject();
private:
    T1 m_functionalObject;
    T2 m_arg1;
    T3 m_arg2;
};

callFunctionalobject可以按如下方式实施:

template<typename T1, typename T2, typename T3>
void Binder<T1,T2,T3>::callFunctionalObject(){
    callImpl(m_functionalObject, m_arg1, m_arg2);
}

callImpl将被重载以识别类型none的对象,以将适当数量的参数传递给功能对象。

现在切换到C ++ 11我不知道如何实现这个事实,在私有部分我有成员,我可以直接访问。

有人能解释我使用C ++ 11或C ++ 14的方式吗?

3 个答案:

答案 0 :(得分:7)

您应该存储std::functionstd::tuple,然后在元组上调用该函数。

这是一个有效的C ++ 14解决方案

#include <iostream>
#include <functional>

template<typename T1, typename ...T>
class Binder
{
public:
    Binder(std::function<T1(T...)> f, std::tuple<T...> t) : m_functional_obj(f), m_parameters(t) {}

    template<std::size_t ...I>
    T1 callImpl(std::index_sequence<I...>) 
    {
        return m_functional_obj(std::get<I>(m_parameters)...);
    }

    T1 callFunctionalObject()
    { 
        return callImpl(std::index_sequence_for<T...>{}); 
    }
private:
    std::function<T1(T...)> m_functional_obj;
    std::tuple<T...>        m_parameters;
};

int test(int i) 
{
    std::cout << "test(" << i << ")" << std::endl;    
    return i + 1;
}

int main()
{
    Binder<int,int> bibi(test, std::make_tuple<int>(2));
    auto res = bibi.callFunctionalObject();
    std::cout << "res is " << res << std::endl;
}

<强> Live code

答案 1 :(得分:4)

我的例子:

// Indices
template <std::size_t... Is>
struct Indices {};

template <std::size_t N, std::size_t... Is>
struct BuildIndices : BuildIndices <N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct BuildIndices<0, Is...> : Indices < Is... > {};

template<class FuncObject, class ... T>
class Binder
{
public:
    Binder(FuncObject funcObject, T... args)
      : m_funcObject(funcObject), m_arguments(std::make_tuple(args...))
    {
    }

    void Call()
    {
      DoCall(BuildIndices<sizeof ... (T)> {});
    }

private:
    template<size_t... Ind>
    void DoCall(Indices<Ind...>)
    {
        return m_funcObject(std::get<Ind>(m_arguments)...);
    }

    FuncObject m_funcObject;
    std::tuple<T...> m_arguments;
};

void Foo(int, char)
{
}

int main()
{
    Binder<void(*)(int, char), int, char> f(Foo, 1, 'd');
    f.Call();

    return 0;
}

答案 2 :(得分:2)

最简单的方法是使用std::function存储具有已设置参数的std::bind对象:

class Binder{
public:
    template <typename T1, typename... T2>
    Binder(T1 functionalObject, T2... args) : f(std::bind(functionalObject, args...)) {}
    void callFunctionalObject() { f(); }
private:
    std::function<void()> f;
};

void foo(int n, std::string s) {
    std::cout << n << " " << s << std::endl;
}

int main()
{
    Binder b(foo, 42, "test");
    b.callFunctionalObject();
}

如果您需要更高级的东西,那么您可能希望将函数参数存储在std::tuple中,然后使用一些模板魔法来解包它,但请指出您在问题中究竟需要什么。

P.S。另请参阅"unpacking" a tuple to call a matching function pointer