对 TC++PL 第 4 版中的 Tuple 示例感到困惑

Confused by Tuple example in TC++PL 4th Edition

我无法准确理解这段代码的工作原理。

我这里有一个较短的示例版本,我认为它符合合理使用的条件:

#include <typeinfo>
#include <iostream>

using namespace std;

struct Nil{};

// Primary template.
template<typename T1=Nil, typename T2=Nil>
struct Tuple : Tuple<T2> {
    T1 x;

    using Base = Tuple<T2>;
    Base* base() { return static_cast<Base*>(this); }
    const Base* base() const { return static_cast<const Base*>(this); }

    Tuple(const T1& t1, const T2& t2) : Base{t2}, x{t1} { }
};

// Specialization.
template<>
struct Tuple<> { Tuple() {} };

// Specialization.
template<typename T1>
struct Tuple<T1> : Tuple<> {
    T1 x;

    using Base = Tuple<>;
    Base* base() { return static_cast<Base*>(this); }
    const Base* base() const { return static_cast<const Base*>(this); }

    Tuple(const T1& t1) : Base{}, x{t1} { }
};

template<typename T1, typename T2>
void print_elements(ostream& os, const Tuple<T1,T2>& t)
{
    os << t.x << ", ";
    print_elements(os,*t.base());
}

template<typename T1>
void print_elements(ostream& os, const Tuple<T1>& t)
{
    os << t.x;
}

template<>
void print_elements(ostream& os, const Tuple<>& t)
{
    os << " ";
}

template<typename T1, typename T2>
ostream& operator<<(ostream& os, const Tuple<T1,T2>& t)
{
    os << "T1: " << typeid(T1).name() << ", T2: " << typeid(T2).name() << "\n";
    os << "{ ";
    print_elements(os,t);
    os << " }";
    return os;
}

int main() {
    cout << Tuple<double, int>{1.1, 22} << "\n";
    cout << Tuple<double>{1.1} << "\n";
    cout << Tuple<>{} << "\n";
}

这个程序的输出是(来自stacked-crooked)

T1: d, T2: i
{ 1.1, 22 }
T1: d, T2: 3Nil
{ 1.1 }
T1: 3Nil, T2: 3Nil
{   }

运算符<<只有一个定义(对于主模板)。

这可以为 Tuple<> 和 Tuple 调用。我的理解是它真的意味着你调用 operator<< 元组和元组。

其次,当为具有默认 (Nil) 类型的元组调用时,它会调用正确的 print_elements。为什么它不调用将输出 Nil 值的 print_elements?

我为 Nil 添加了一个运算符 <<,这并没有改变行为。

谢谢!

这就是工作原理 print_elementsTuple 有两个元素的重载,Tuple 有一个元素(第二个为 Nil),Tuple 有零个元素(均为 Nil)的重载。

operator <<中:

tTuple<T1, T2>时,则调用print_elements<Tuple<T1, T2> >

tTuple<T1>(实际上是Tuple<T1, Nil>),那么print_elements<Tuple<T1> >会被调用,因为这个版本比print_elements<Tuple<T1, T2> >更好,其中T2Nil;

tTuple<>(实际上是Tuple<Nil, Nil>),然后print_elements<Tuple<> >会被调用,因为这个版本比另一个版本更好。