对 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_elements
。
Tuple
有两个元素的重载,Tuple
有一个元素(第二个为 Nil),Tuple
有零个元素(均为 Nil)的重载。
在operator <<
中:
当t
为Tuple<T1, T2>
时,则调用print_elements<Tuple<T1, T2> >
;
当t
是Tuple<T1>
(实际上是Tuple<T1, Nil>
),那么print_elements<Tuple<T1> >
会被调用,因为这个版本比print_elements<Tuple<T1, T2> >
更好,其中T2
是 Nil
;
当t
是Tuple<>
(实际上是Tuple<Nil, Nil>
),然后print_elements<Tuple<> >
会被调用,因为这个版本比另一个版本更好。
我无法准确理解这段代码的工作原理。
我这里有一个较短的示例版本,我认为它符合合理使用的条件:
#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_elements
。
Tuple
有两个元素的重载,Tuple
有一个元素(第二个为 Nil),Tuple
有零个元素(均为 Nil)的重载。
在operator <<
中:
当t
为Tuple<T1, T2>
时,则调用print_elements<Tuple<T1, T2> >
;
当t
是Tuple<T1>
(实际上是Tuple<T1, Nil>
),那么print_elements<Tuple<T1> >
会被调用,因为这个版本比print_elements<Tuple<T1, T2> >
更好,其中T2
是 Nil
;
当t
是Tuple<>
(实际上是Tuple<Nil, Nil>
),然后print_elements<Tuple<> >
会被调用,因为这个版本比另一个版本更好。