【问题标题】:Variadic Templates - different types of expansion可变参数模板 - 不同类型的扩展
【发布时间】:2012-03-27 21:14:21
【问题描述】:

Andrei Alexandrescu 做了一场精彩的演讲,题为:Variadic Templates are Funadic

他提出了以下三个不同的扩展:

template <class... Ts> void fun( Ts... vs ) {
    gun( A<Ts...>::hun(vs)...);
    gun( A<Ts...>::hun(vs...));
    gun( A<Ts>::hun(vs)...);
}

他解释说:

呼叫 1: 扩展所有Ts 以实例化class A, 然后拨打hun(vs) 然后在将所有参数传入gun时再次展开所有参数

呼叫 2: 分别展开所有Ts 和所有vs

调用 3: 以锁步扩展,即: 展开 Ts 的参数 1 和 vs 的参数 1 展开 Ts 的参数 2 和 vs 的参数 2 展开Ts的参数n和vs的参数n

关于可变参数模板的其他讨论似乎只涵盖了简单的可变参数类模板和可变参数函数,例如 typesafe printf 等。我不确定这些不同类型的扩展如何影响代码以及每种类型的用处。

有没有人有一些例子来展示每种扩展类型的应用?

【问题讨论】:

  • @KennyTM 不是重复的。这家伙想要每种扩展类型的示例(不一定只有 alexandrescu 展示的那三种,他展示的只是两种类型的扩展(一种进入模板参数列表,另一种进入函数参数列表)。
  • ...但是当他接受一个只显示这两种扩展类型的答案时,我猜要么问题不精确,要么我对问题缺乏理解,或者两者兼而有之......

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


【解决方案1】:
#include <iostream>
#include <memory>
#include <typeinfo>
#include <cstdlib>
#include <cxxabi.h>

template <typename T>
std::unique_ptr<char, void(*)(void*)>
type_name()
{
    return std::unique_ptr<char, void(*)(void*)>
           (
                __cxxabiv1::__cxa_demangle(typeid(T).name(), nullptr,
                                           nullptr, nullptr),
                std::free
           );
}

void display() {}

template <class T>
void
display()
{
    std::cout << type_name<T>().get() << ' ';
}

template <class T, class T2, class ...Tail>
void
display()
{
    std::cout << type_name<T>().get() << ' ';
    display<T2, Tail...>();
}

template <class... Ts>
struct A
{
    template <class... Us>
        static
        int
        hun(Us... us)
        {
            std::cout << "A<";
            display<Ts...>();
            std::cout << ">::hun(";
            display<Us...>();
            std::cout << ")\n";
            return 0;
        }
};

template <class ...T>
void gun(T...) {}

template <class... Ts> void fun( Ts... vs )
{
    std::cout << "gun( A<Ts...>::hun(vs)...);\n";
    gun( A<Ts...>::hun(vs)...);
    std::cout << "\ngun( A<Ts...>::hun(vs...));\n";
    gun( A<Ts...>::hun(vs...));
    std::cout << "\ngun( A<Ts>::hun(vs)...);\n";
    gun( A<Ts>::hun(vs)...);
}

int main()
{
    fun(1, 'a', 2.3);
}

输出:

gun( A<Ts...>::hun(vs)...);
A<int char double >::hun(int )
A<int char double >::hun(char )
A<int char double >::hun(double )

gun( A<Ts...>::hun(vs...));
A<int char double >::hun(int char double )

gun( A<Ts>::hun(vs)...);
A<int >::hun(int )
A<char >::hun(char )
A<double >::hun(double )

【讨论】:

  • 第二个扩展看起来很简单。其他两个很有趣,但如果在生产代码中使用可能会导致混淆。您是否希望在现实世界中看到这一点?
  • 我很难说。我猜我们作为一个行业可能仍在学习如何使用可变参数模板。几年后,有人可能会发现一种非常巧妙的方式来使用其他两种形式,并且它可能会成为一种模式。在 98 年,我从来没有想过我会使用像 enable_if 这样的东西,但我现在一直都在这样做。 C++ 是一种活生生的、不断发展的语言! :-)
【解决方案2】:

情况 2 和 3 在涉及可变参数包的任何类型的代码中都非常常见。

template<typename... T>
void f(T&&... t)
{
    // Case 2:
    auto t2 = std::tuple<T...>(t...);

    // Case 3:
    auto t3 = std::make_tuple(std::forward<T>(t)...);
}

查看我自己的代码,我找不到案例 1 的任何幸存示例。我过去可能在一些 detail 命名空间中使用它作为帮助模板,但我不确定。我认为大多数时候它不会很常见,甚至没有必要。

【讨论】:

    猜你喜欢
    • 2014-04-12
    • 1970-01-01
    • 2013-02-07
    • 2014-10-30
    • 2013-10-03
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    相关资源
    最近更新 更多