简体   繁体   English

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

[英]Expanding an STL container into a variadic template

To keep things generic and straightforward, say that I have a std::vector of integers, such as: 为了保持通用和简单,请说我有一个整数的std :: vector,例如:

std::vector<int> v;

Now, what I am wondering is, is it possible to take n (where n is a constant known at compile time) values from v and pass them to an arbitrary function? 现在,我想知道的是,是否有可能从v中取n(其中n是编译时已知的常量)值并将它们传递给任意函数? I know that this is doable with variadic templates: 我知道这对于可变参数模板是可行的:

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

And then we hope 'pass' is called with exactly 3 integers. 然后我们希望'pass'被调用正好3个整数。 The details don't matter so much. 细节并不重要。 What I am wondering is, is the following somehow doable: 我想知道的是,以下是某种可行的方式:

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

Where ... is being used like a variadic template? 哪里......被用作可变参数模板? Essentially, I'm asking if I can 基本上,我问我是否可以

  1. Expand a std::vector or other STL container into a variadic template with n elements 将std :: vector或其他STL容器展开为具有n个元素的可变参数模板
  2. And/or in-order pass these values directly to a function being called 和/或按顺序将这些值直接传递给被调用的函数

Is this possible with C++11? 这可能与C ++ 11一起使用吗? Noting that I need this to work on MSVC v120/VS2013. 注意到我需要这个在MSVC v120 / VS2013上工作。

It's definitely possible, but you cannot determine the safety of doing it at compile time. 这绝对是可能的,但你无法确定在编译时这样做的安全性。 This is, as WhozCraig says, because the vector lacks a compile-time size. 正如WhozCraig所说,这是因为向量缺少编译时的大小。

I'm still trying to earn my template meta programming wings, so I may have done things a little unusually. 我仍然试图获得我的模板元编程翅膀,所以我可能做了一些不寻常的事情。 But the core idea here is to have a function template recursively invoke itself with the next item in the vector until it has built up a parameter pack with the desired parameters. 但这里的核心思想是让一个函数模板以向量中的下一个项目递归调用自身,直到它构建了一个带有所需参数的参数包。 Once it has that, it's easy to pass it to the function in question. 一旦有了,就很容易将它传递给相关函数。

The implementation of the core here is in apply_first_n , which accepts a target std::function<R(Ps...)> , and a vector, and a parameter pack of Ts... . 这里核心的实现是在apply_first_n ,它接受一个目标std::function<R(Ps...)> ,一个向量,以及一个Ts...的参数包。 When Ts... is shorter than Ps... it builds up the pack; Ts...Ps...Ps...它会积累包裹; once it's the same size, it passes it to the function. 一旦它的大小相同,它就会将它传递给函数。

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)...);
}

You call this with, eg, apply_first_n(std::function<int(int, int)>(f), v); 你可以用例如apply_first_n(std::function<int(int, int)>(f), v);调用它apply_first_n(std::function<int(int, int)>(f), v); . In the live example , make_fn just makes the conversion to std::function easier, and ProcessInts is a convenient testing function. 实例中make_fn只是简单地转换为std::function ,而ProcessInts是一个方便的测试函数。

I'd love to figure out how to avoid the use of std::function , and to repair any other gross inefficiencies that exist. 我想知道如何避免使用std::function ,并修复存在的任何其他严重低效问题。 But I'd say this is proof that it's possible. 但我要说这证明它是可能的。


For reference, I took the above approach further, handling set , vector , tuple , and initializer_list , as well as others that match the right interfaces. 作为参考,我进一步采用了上述方法,处理setvectortupleinitializer_list ,以及匹配正确接口的其他方法。 Removing std::function seemed to require the func_info traits class, as well as several overloads. 删除std::function似乎需要func_info traits类,以及几个重载。 So while this extended live example is definitely more general, I'm not sure I'd call it better. 因此,虽然这个扩展的实例肯定更加通用,但我不确定我会把它称为更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM