假设我有以下函数模板:
template<typename T>
void mutate(T& t) { /*...*/ }
我有以下类模板:
template<typename... Args>
class Processor {
std::tuple<Args...> tup;
// call mutate on the ith tuple element
void process(size_t i) {
mutate(std::get<i>(tup)); // ERROR
}
}
这不起作用,因为 process
的 i
参数不是常量表达式。 (它不能是常量表达式,因为 i
直到运行时才知道)
在不修改process
或mutuate
的签名的情况下,是否有某种方法可以有效地完成这项工作?即如何更改 process
的实现,以便它在 tup
的第 i
成员上调用 mutate
?
最佳答案
您需要获取运行时索引并将其提升为常量表达式。最简单的方法就是使用 Boost.Mp11它附带了一个专门用于此目的的函数:
template<typename... Args>
class Processor {
std::tuple<Args...> tup;
// call mutate on the ith tuple element
void process(size_t i) {
mp_with_index<sizeof...(Args)>(i, [&](auto I){
mutate(std::get<I>(tup));
});
}
}
mp_with_index
的作用是采用常量表达式表示最大大小 (sizeof...(Args)
) 和运行时大小 (i
) code>),然后使用一个整型常量调用您的可调用对象(lambda),该常量是将运行时大小提升为常量表达式。
这可以使用 std::index_sequence
自行实现,方法是构建函数指针数组,然后调用正确的指针:
template <size_t... Is, typename F>
decltype(auto) mp_with_index(size_t i, F f, std::index_sequence<Is...>) {
using R = decltype(f(std::integral_constant<size_t, 0>{}));
using P = R(*)(F&);
static constexpr P fns[] = {
+[](F& f) -> R { return f(std::integral_constant<size_t, Is>{}); }...
};
return fns[i](f);
}
template <size_t N, typename F>
decltype(auto) mp_with_index(size_t i, F f) {
return mp_with_index(i, f, std::make_index_sequence<N>());
}
(请注意,Boost.Mp11 实现比这更好,这只是功能上正确的)。
关于c++ - 当 i 不是常量表达式时寻址 std::tuple 的第 i 个成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58585380/