假设我有以下功能模板:
template<typename T>
void mutate(T& t) { /*...*/ }
Run Code Online (Sandbox Code Playgroud)
并且我有以下课程模板:
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
}
}
Run Code Online (Sandbox Code Playgroud)
这是行不通的,因为的i参数process不是常量表达式。(它不能是一个常量表达式,因为i直到运行时才知道)
在不修改process或的签名的情况下mutuate,是否可以有效地完成这项工作?即我如何更改实现process以使其调用mutate的ith成员tup?
您需要获取运行时索引并将其提升为常量表达式。最简单的方法是只使用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));
});
}
}
Run Code Online (Sandbox Code Playgroud)
要做的mp_with_index是对最大大小(sizeof...(Args))和运行时大小(i)进行常量表达式,然后使用整数常量(即运行时大小提升为常量表达式)来调用可调用对象(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>());
}
Run Code Online (Sandbox Code Playgroud)
(请注意,Boost.Mp11实现比这更好,这在功能上是正确的)。
借助一些辅助功能,我们可以做到。
#include <tuple>
#include <iostream>
template<typename T>
void mutate(T& t)
{
std::cout << typeid(t).name() << "\n";
}
template<typename T, std::size_t... Seq>
void processes_each(int i, T& t, std::index_sequence<Seq...> const&)
{
bool discard[] = { false,
(i == Seq ? (mutate(std::get<Seq>(t)), true) : false) ...
};
(void)discard;
}
template<typename... Args>
class Processes
{
std::tuple<Args...> tup;
public:
void process(size_t i) {
processes_each(i, tup, std::make_index_sequence<sizeof...(Args)>());
}
};
int main()
{
Processes<int, double> p1;
p1.process(0);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
110 次 |
| 最近记录: |