在可变参数模板函数中为每个模板类型调用void函数?

时间:2015-02-16 17:54:22

标签: c++ templates variadic-templates

我的目标是编写一个简单的通用函数来注册任意C ++类型的转换器。为简单起见,我只打印C ++类型名称。我希望能够为任何类型调用我的通用print_type_name函数,包括一次包含多种类型(可变参数):

template <typename T>
void print_type_name(void)
{
    std::cout << typeid(T).name() << std::endl;
}

这适用于这样的事情:

print_type_name<int>();
print_type_name<std::string>();
print_type_name<std::vector<std::complex<float> > >();

但是,我需要能够为可变参数模板中的每种类型调用此函数,例如(扩展时):

print_type_name<int, std::string, std::vector<std::complex<float> > >();

这是我提出的问题,但它相当笨重:

template <typename ...TS>
void noop(TS... ts) { }

template <typename T>
int real_print_type_name(void) {
    std::cout << typeid(T).name() << std::endl;
    return 0;
}

template <typename ...TS>
void print_type_name(void) {
    noop(real_print_type_name<TS>()...);
}

允许以下内容:

template <typename ...TS>
void other_function(void) {
    print_type_name<TS...>();
}

注意无用的noop函数和int返回类型 real_print_type_name,我必须添加这两个才能扩展 参数包。有没有更简洁的方法呢?

3 个答案:

答案 0 :(得分:4)

template <typename ...TS>
void print_type_name() {
    using expander = int[];
    (void) expander{ 0, (std::cout << typeid(TS).name() << '\n', 0)... };
}

或者,C ++ 17风格:

template <typename ...TS>
void print_type_name(void) {
    (std::cout << ... << (typeid(TS).name() + "\n"s));
}

Demo

答案 1 :(得分:4)

这是一个辅助函数。它使用随机黑暗魔法,但它的名字很清楚:

void do_in_order() {}

template<class...Fs>
void do_in_order( Fs&&...fs ) {
  using discard=int[];
  (void)discard{0, (void(
    std::forward<Fs>(fs)()
  ),0)... };
}

或在C ++ 17中:

template<class...Fs>
void do_in_order( Fs&&...fs ) {
  (void(std::forward<Fs>(fs)())...);
}

(好多了)。

隐藏任何丑陋。它需要一组void()可调用和调用 它们从左到右 - 它按顺序执行任务,就像在锡上说的那样。

然后print_type_names成为:

template<class...Ts>
void print_type_names() {
  do_in_order( print_type_name<Ts>... );
}

template<class...Ts>
void print_type_names() {
  do_in_order( [&]{
    std::cout << typeid(Ts).name() << std::endl;
  }... );
}

如果您不想使用单个print_type_name功能并想要内联它。

请注意,一些不符合规范的编译器抱怨在...中扩展整个lambda。

live example

答案 2 :(得分:2)

我认为你可以这样做:

void print_type_name()
{
    std::cout<<"\n";
}

template <typename T>
void print_type_name(const T& t)
{
    std::cout<<t<<" : of type "<<typeid(t).name()<<"\n";
}

template <typename T1, typename... Ts>
void print_type_name(const T1& t1, const Ts&... ts)
{
    // Head
    std::cout<<t1<<" : of type "<<typeid(t1).name()<<", ";
    // Tail
    print_type_name(ts...);
}

是否更清楚我不知道。