为了保持通用和直接,假设我有一个整数 std::vector,例如:
std::vector<int> v;
现在,我想知道的是,是否可以从 v 中获取 n(其中 n 是编译时已知的常量)值并将它们传递给任意函数?我知道这对于可变参数模板是可行的:
template<typename... T>
void pass(void (*func)(int, int, int), T... t) {
func(t...);
}
然后我们希望使用恰好 3 个整数调用“pass”。细节并不重要。我想知道的是,以下是否可行:
void pass(void (*func)(int, int, int), std::vector<int> &t) {
auto iter = t.begin();
func((*iter++)...);
}
在哪里...像可变参数模板一样使用?本质上,我是在问我是否可以
- 将 std::vector 或其他 STL 容器扩展为具有 n 个元素的可变参数模板
- 和/或按顺序将这些值直接传递给被调用的函数
这在 C++11 中可行吗?请注意,我需要它才能在 MSVC v120/VS2013 上工作。
最佳答案
这绝对是可能的,但你无法确定在编译时这样做是否安全。正如 WhozCraig 所说,这是因为 vector 缺少编译时大小。
我仍在尝试赢得模板元编程的翅膀,所以我可能做了一些不寻常的事情。但这里的核心思想是让一个函数模板递归地使用 vector 中的下一项调用自身,直到它用所需的参数构建了一个参数包。一旦有了它,就很容易将它传递给有问题的函数。
这里核心的实现在apply_first_n
, 它接受一个目标 std::function<R(Ps...)>
,和一个 vector ,以及一个 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::function
更容易,而且ProcessInts
是一个方便的测试函数。
我很想知道如何避免使用 std::function
,并修复存在的任何其他严重低效问题。但我想说这证明了这是可能的。
作为引用,我进一步采用了上述方法,处理 set
, vector
, tuple
, 和 initializer_list
,以及其他匹配正确接口(interface)的。删除 std::function
似乎需要 func_info
特征类,以及几个重载。所以虽然这个 extended live example肯定更一般,我不确定我会称之为更好。
关于c++ - 将 STL 容器扩展为可变参数模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23946300/