我有以下伪代码:
template <typename... Ts>
void f(int index) {
std::vector<std::function<void(void)>> funcs;
funcs.push_back([](){ std::cout << typeid(type_1).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_2).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_3).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_4).name() << std::endl; });
funcs[index]();
}
想象一下,Ts...
参数包包含type_1
,type_2
,type_3
和type_4
。
如何扩展参数包以实现这样的效果?我的意思是 - 如果模板包中有4个参数,并且在不同的lambdas中有不同的类型,我怎么能得到4 push_back()
个调用?我不知道语法..
我是否可以在编译时获得某种类型的此类函数,因此运行时没有push_backs?
C ++ 17解决方案没问题,但C ++ 14最好。
答案 0 :(得分:3)
对于C ++ 17,我想是这样的事情
(funcs.push_back([](){ std::cout << typeid(Ts).name() << std::endl; }), ...);
或更好(恕我直言),使用emplace_back()
(funcs.emplace_back([](){ std::cout << typeid(Ts).name() << std::endl; }), ...);
但记得那是
std::vector<std::function<void(void)>>
不
std::vector<std::function<void>>
在C ++ 14(和C ++ 11)中,您可以获得类似于未使用数组的初始化技巧;该函数可以写成
template <typename ... Ts>
void f (int index)
{
using unused = int[];
std::vector<std::function<void(void)>> funcs;
(void)unused { 0, (funcs.emplace_back([]()
{ std::cout << typeid(Ts).name() << std::endl; }), 0)... };
funcs[index]();
}
答案 1 :(得分:1)
更新
从重新阅读问题开始,我认为你只想为第一种类型调用该函数。
在哪种情况下,它在编译时是微不足道的:
#include <array>
#include <type_traits>
#include <iostream>
#include <string>
template <class T>
void show_type()
{
std::cout << typeid(T).name() << std::endl;
}
template <typename... Ts>
void f(int index) {
using function_type = void(*)();
constexpr auto size = sizeof...(Ts);
constexpr std::array<function_type, size> funcs =
{
&show_type<Ts>...
};
funcs[index]();
}
int main()
{
for(int i = 0 ; i < 3 ; ++i)
f<int, double, std::string>(i);
}
示例输出:
i
d
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
答案 2 :(得分:1)
如果您要做的只是为模板参数包中的n
类型执行某些操作,其中n
是运行时变量,那么vector
+ {{1}方法并不是很好。最好在那里添加索引序列并折叠:
function
这种结构允许您添加一个失败案例,您可以使用某种特殊类型调用传入函数:
template <typename T> struct tag_t { using type = T; };
template <typename T> constexpr inline tag_t<T> tag{};
template <class F, size_t... Is, typename... Tags>
void match(F f, size_t i, std::index_sequence<Is...>, Tags... tags) {
auto inner = [&](auto tag) { f(tag); return true; };
bool matched = ((i == Is && inner(tags)) || ...);
if (!matched) {
// failure case?
}
}
template <typename... Ts, class F>
void match(F f, size_t i) {
return match(f, i, std::index_sequence_for<Ts...>(), tag<Ts>... );
}
template <typename... Ts>
void foo(int index) {
match<Ts...>([](auto tag){
std::cout << typeid(typename decltype(tag)::type).name() << std::endl;
}, index);
}