将STL容器扩展为可变参数模板

时间:2014-05-30 02:54:24

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

为了保持通用和简单,请说我有一个整数的std :: vector,例如:

std::vector<int> v;

现在,我想知道的是,是否可以从v中取n(其中n是编译时已知的常量)值并将它们传递给任意函数?我知道这对于可变参数模板是可行的:

template<typename... T>
void pass(void (*func)(int, int, int), T... t) {
  func(t...);
}

然后我们希望'pass'被调用正好3个整数。细节并不重要。我想知道的是,以下是某种可行的方式:

void pass(void (*func)(int, int, int), std::vector<int> &t) {
  auto iter = t.begin();
  func((*iter++)...);
}

哪里......被用作可变参数模板?基本上,我问我是否可以

  1. 将std :: vector或其他STL容器展开为具有n个元素
  2. 的可变参数模板
  3. 和/或按顺序将这些值直接传递给被称为
  4. 的函数

    C ++ 11可以实现吗?注意到我需要这个在MSVC v120 / VS2013上工作。

1 个答案:

答案 0 :(得分:6)

这绝对是可能的,但你无法确定在编译时这样做的安全性。正如WhozCraig所说,这是因为向量缺少编译时的大小。

我仍然试图获得我的模板元编程翅膀,所以我可能做了一些不寻常的事情。但这里的核心思想是让一个函数模板以向量中的下一个项目递归调用自身,直到它构建了一个带有所需参数的参数包。一旦有了,就很容易将其传递给相关函数。

核心的实施位于apply_first_n,它接受​​目标std::function<R(Ps...)>,矢量和参数包Ts...。当Ts...短于Ps...时,它会构建包;一旦它的大小相同,它就会将它传递给函数。

template <typename R, typename... Ps, typename... Ts>
typename std::enable_if<sizeof...(Ps) == sizeof...(Ts), R>::type
apply_first_n(std::function<R(Ps...)> f, const std::vector<int> &v, Ts&&... ts)
{
    if (sizeof...(Ts) > v.size())
        throw std::out_of_range("vector too small for function");
    return f(std::forward<Ts>(ts)...);
}

template <typename R, typename... Ps, typename... Ts>
typename std::enable_if<sizeof...(Ps) != sizeof...(Ts), R>::type
apply_first_n(std::function<R(Ps...)> f, const std::vector<int> &v, Ts&&... ts)
{
    const int index = sizeof...(Ps) - sizeof...(Ts) - 1;
    static_assert(index >= 0, "incompatible function parameters");
    return apply_first_n(f, v, *(std::begin(v) + index), std::forward<Ts>(ts)...);
}

您可以使用例如apply_first_n(std::function<int(int, int)>(f), v);来调用它。在live example中,make_fn只是简单地转换为std::functionProcessInts是一种方便的测试功能。

我很想知道如何避免使用std::function,并修复存在的任何其他严重低效问题。但我说这可以证明它是可能的。


作为参考,我进一步采用了上述方法,处理setvectortupleinitializer_list以及与正确接口匹配的其他方法。删除std::function似乎需要func_info traits类,以及几个重载。因此虽然这extended live example肯定更为一般,但我不确定我是否会更好地称呼它。