如何基于模板变量参数多次扩展语句

时间:2017-11-26 18:12:06

标签: c++ c++11 c++14 variadic-templates c++17

我有以下伪代码:

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_1type_2type_3type_4

如何扩展参数包以实现这样的效果?我的意思是 - 如果模板包中有4个参数,并且在不同的lambdas中有不同的类型,我怎么能得到4 push_back()个调用?我不知道语法..

我是否可以在编译时获得某种类型的此类函数,因此运行时没有push_backs?

C ++ 17解决方案没问题,但C ++ 14最好。

3 个答案:

答案 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);
}