将STL容器扩展为可变参数模板 [英] Expanding an STL container into a variadic template
问题描述
为使事情通用且简单,请说我有一个整数的std :: vector,例如:
To keep things generic and straightforward, say that I have a std::vector of integers, such as:
std::vector<int> v;
现在,我想知道的是,是否可以取n(其中n是一个已知的常数在编译时)从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? I know that this is doable with variadic templates:
template<typename... T>
void pass(void (*func)(int, int, int), T... t) {
func(t...);
}
然后我们希望 pass正好用3个整数调用。细节无关紧要。我想知道的是,以下某种方式可行:
And then we hope 'pass' is called with exactly 3 integers. 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
- 将std :: vector或其他STL容器扩展为具有n个元素的可变参数模板
- 和/或有序地将这些值直接传递给被调用的函数
这可能吗用C ++ 11?注意,我需要在MSVC v120 / VS2013上使用它。
Is this possible with C++11? Noting that I need this to work on MSVC v120/VS2013.
推荐答案
肯定有可能,但是您不能确定这样做的安全性它在编译时。正如WhozCraig所说,这是因为向量缺少编译时大小。
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.
我仍在尝试赚取模板元编程的翅膀,所以我可能已经做了事情有点不寻常。但是这里的核心思想是让函数模板递归调用向量中的下一个项目,直到它建立了具有所需参数的参数包为止。一旦有了它,就很容易将其传递给所讨论的函数。
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.
此处的核心实现在 apply_first_n $ c中$ c>,它接受目标
std :: function< R(Ps ...)>
,向量和 Ts ...
。当 Ts ...
短于 Ps ...
时,它构成了背包;
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...
. When Ts...
is shorter than Ps...
it builds up the pack; 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)...);
}
您可以用 apply_first_n(std :: function< int(int,int)>(f),v);
。在实时示例中, make_fn
只是使转换为 std :: function
更容易,而 ProcessInts
是方便的测试功能。
You call this with, e.g., 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.
我很想弄清楚如何避免使用 std :: function
,并修复存在的任何其他效率低下的问题。
I'd love to figure out how to avoid the use of std::function
, and to repair any other gross inefficiencies that exist. But I'd say this is proof that it's possible.
作为参考,我进一步采用了上述方法,处理了 set
, vector
,元组
和 initializer_list
,以及与正确接口匹配的其他文件。删除 std :: function
似乎需要 func_info
traits类,以及一些重载。因此,尽管扩展的实时示例肯定更笼统,但我不确定我是否愿意叫它更好。
For reference, I took the above approach further, handling set
, vector
, tuple
, and initializer_list
, as well as others that match the right interfaces. Removing std::function
seemed to require the func_info
traits class, as well as several overloads. So while this extended live example is definitely more general, I'm not sure I'd call it better.
这篇关于将STL容器扩展为可变参数模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!