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

Variadic templates - how can I create type, that stores passed arguments

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

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 执行相同的操作吗?

您应该存储一个 std::function 和一个 std::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

最简单的方法是使用 std::bind:

存储带有已设置参数的 std::function 对象
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

我的例子:

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