Chapter2 Class Templates
Friends
template<typename> struct Point;
template<typename T> std::ostream& operator<< (std::ostream& os, const Point<T>& point);
template<typename T>
struct Point
{
Point(T x, T y)
: x_{x}, y_{y}
{}
friend std::ostream& operator<< <T>(std::ostream& os, const Point<T>& point);
private:
T x_;
T y_;
};
template<typename T> std::ostream& operator<< (std::ostream& os, const Point<T>& point)
{
os << "{ x: " << point.x_ << ", y: " << point.y_ << " }";
return os;
}
int main()
{
Point point{ 1, 2 }; // C++17 implicit deduction guides, T is int.
std::cout << point << '\n';
}
注意
<T>
与函数名operator<<
绑定,因此,这里声明了一个具体化的非成员函数模板作为friend
,如果不加上<T>
那么,结果是这里就将时声明一个新的非模板函数作为friend
。
Class Template Argument Deduction
template<typename T>
struct Foo
{
Foo()
: x_{}
{}
Foo(T x)
: x_{x} // #2
{}
T x_;
};
Foo() -> Foo<int>; // #1
int main()
{
Foo foo{}; // explicit, use #1
Foo bar{233}; // implicit, use #2
}
注意
- 1, 和函数模板不同,类模板参数不能只指定部分
template<typename T, typename U>
struct Foo
{
Foo(T x, U y)
: x_{x}, y_{y}
{}
T x_;
U y_;
};
int main()
{
Foo<int> foo{2, 2.33}; // ERROR! U has no default type.
}
- 2, string literals
template<typename T>
struct Foo
{
Foo(const T&)
{
static_assert(std::is_same_v<T, char[4]>);
}
};
template<typename T>
struct Bar
{
Bar(T)
{
static_assert(std::is_same_v<T, const char*>);
}
};
int main()
{
Foo foo = "foo"; // foo is `Foo<const char[4]>`
Bar bar = "bar"; // bar is `Bar<const char*>`
}
注意
模板参数通过引用传递,那么这个参数不会decay
,因此,foo
的类型推断为const char[4]
。而通过值传递const char[4]
将会decay为const char*
- 3, deduction guide
为了解决类型推断中传递raw pointer带来的问题,可以显式的自定义推断规则:
#include <string>
template<typename T>
struct Foo
{
Foo() = default;
Foo(const T& t)
: x_{t}
{}
T x_;
};
Foo(const char*) -> Foo<std::string>;
int main()
{
Foo foo = "foo";
}
以上代码将T
推断为std::string
,然而,仍然不能通过编译:
c.cc: In function ‘int main()’:
c.cc:19:13: error: conversion from ‘const char [4]’ to non-scalar type ‘Foo<std::__cxx11::basic_string<char> >’ requested
Foo foo = "foo";
这里必须将foo = "foo"
更改为foo{"foo"}
Templatized Aggregate
聚合类也可以是模板类,从C++17起,可以为聚合类定义推断规则
template<typename T>
struct Foo
{
T x;
std::string y;
};
Foo(const char*, const char*) -> Foo<std::string>;
int main()
{
Foo foo = {"233", "233"};
}
aggregate classes: > classes/structs with no user-provided, explicit, or inherited constructors, no private or protected nonstatic data members, no virtual functions, and no virtual, private, or protected base classes.