NamedType源码解读
上一篇博文中介绍了Strong Type的一些基本思想,并提到了开源库NamedType
C++ 编程技巧之StrongType(1)-CSDN博客,本篇文章我们来分析一下NamedType
的源码实现。
NamedType用法
我们先看几个NamedType的简单用法
TEST_CASE("Addable")
{
using AddableType = fluent::NamedType<int, struct AddableTag, fluent::Addable>;
AddableType s1(12);
AddableType s2(10);
REQUIRE((s1 + s2).get() == 22);
REQUIRE((+s1).get() == 12);
}
TEST_CASE("Printable")
{
using StrongInt = fluent::NamedType<int, struct StrongIntTag, fluent::Printable>;
std::ostringstream oss;
oss << StrongInt( 42 );
CHECK(oss.str() == "42");
}
TEST_CASE("PreIncrementable")
{
using StrongInt = fluent::NamedType<int, struct StrongIntTag, fluent::PreIncrementable>;
StrongInt a{1};
StrongInt b = ++a;
CHECK( a.get() == 2 );
CHECK( b.get() == 2 );
}
自定义的NamedType通过选择一些继承的Skill类,就具有了相应的增强技能,这是一种通过继承来获取基类能力的方式。
NamedType实现解析
首先看一下NamedType模版类的定义,开门被雷暴击的感觉,这fucking啥玩意?
template <typename T, typename Parameter, template <typename> class... Skills>
class FLUENT_EBCO NamedType : public Skills<NamedType<T, Parameter, Skills...>>...
{
public:
using UnderlyingType = T;
……
}
模板参数详解
template <typename T, typename Parameter, template <typename> class... Skills>
class NamedType : public Skills<NamedType<T, Parameter, Skills...>>...
模板参数说明:
类型T
:
- 表示一个基础类型(
UnderlyingType
),该类型表示底层存储的实际数据类型,例如int
或std::string
。
Parameter
:
- 一个辅助参数,用于区分不同的
NamedType
实例,即使它们具有相同的底层类型T
。
template <typename> class... Skills
:
- 是一个模板类的 参数包,表示可以传入多个模板类作为参数。
- 这些模板类必须是形如
template <typename> class Skill
的单参数模板。 - 参数包
Skills
支持任意数量的模板类,可以为空。
类的继承
class NamedType : public Skills<NamedType<T, Parameter, Skills...>>...
继承分析:
- 这里
NamedType
通过...
展开继承了 所有Skills
模板类实例化后的类型。 - 每个
Skill
模板类会以当前的NamedType
类型作为其模板参数进行实例化:
Skills<NamedType<T, Parameter, Skills...>> //CRPT模版
- 这种继承机制允许将多种功能(由
Skills
模板类定义)混入到NamedType
中,实现 功能扩展。
定义一个 NamedType
实例:
using StrongInt = fluent::NamedType<int, struct StrongIntTag, fluent::Printable, fluent::Addable>;
class NamedType : public Printable<NamedType<int, StrongIntTag, Printable, Addable>>,
public Addable<NamedType<int, StrongIntTag, Printable, Addable>> {
...
};
class Printable<NamedType<int, StrongIntTag, Printable, Addable>> :
crtp<NamedType<int, StrongIntTag, Printable, Addable>, Printable>
class Addable<NamedType<int, StrongIntTag, Printable, Addable>> :
crtp<NamedType<int, StrongIntTag, Printable, Addable>, Addable>
成员类型定义
using UnderlyingType = T;
- 定义
UnderlyingType
,便于外界访问实际存储的数据类型。
构造函数
NamedType() = default;
默认构造函数,允许空对象的创建。
explicit constexpr NamedType(T const& value) noexcept(std::is_nothrow_copy_constructible<T>::value)
: value_(value) {}
- 使用左值构造
NamedType
实例。 - 如果
T
可无异常复制,则构造函数被标记为noexcept
。
template <typename T_ = T, typename = IsNotReference<T_>>
explicit constexpr NamedType(T&& value) noexcept(std::is_nothrow_move_constructible<T>::value)
: value_(std::move(value)) {}
- 使用右值构造
NamedType
实例。 - 为避免引用类型的冲突,通过
IsNotReference
限制T
必须是非引用类型。
访问接口
constexpr T& get() noexcept;
constexpr std::remove_reference_t<T> const& get() const noexcept;
- 提供两种
get
方法: get()
返回底层类型的非const
引用。get() const
返回底层类型的const
引用。
类型转换
using ref = NamedType<T&, Parameter, Skills...>;
operator ref() { return ref(value_); }
- 将当前
NamedType
实例隐式转换为一个引用类型(NamedType<T&, Parameter, Skills...>
)。 - 这使得可以将
NamedType
对象直接传递到需要引用的地方。
argument
内嵌结构体
struct argument {
NamedType operator=(T&& value) const {
return NamedType(std::forward<T>(value));
}
template <typename U>
NamedType operator=(U&& value) const {
return NamedType(std::forward<U>(value));
}
// ...
};
- 内嵌结构体
argument
用于支持命名参数的语法。 - 通过
operator=
重载,创建一个新的NamedType
实例。
这个argument在这里有点莫名其妙,但是还是有点东西,我们后面再讲。
私有成员
T value_;
- 存储实际的数据值,类型为模板参数
T
。
辅助工具解析
make_named
template <template <typename T> class StrongType, typename T>
constexpr StrongType<T> make_named(T const& value) {
return StrongType<T>(value);
}
- 提供一种简便的方法,通过给定值创建
NamedType
。 - 适用于代码中需要快速创建
NamedType
的场景。 - 可以类比make_unique_ptr<>来理解
Skills拓展类实现
- Incrementable<T>,可增性
- PreIncrementable<T>, ++i
- PostIncrementable<T>, i++
- Decrementable<T>,可减性
- PreDecrementable<T>, --i
- postDecrementable<T>, i --
- Addable<T>, a+b
- Subtractable<T> , a -b
- Multiplicable<T> a*b
- Divisible<T> a/b
- Modulable<T> a%b
- BitWiseInvertable<T>
- BitWiseAndable<T>
- BitWiseOrable<T>
- BitWiseXorable<T>
- BitWiseLeftShiftable<T>
- BitWiseRightShiftable<T>
- Comparable<T>
- Printable<T>
- Hashable<T>
这些Skill的实现也很简单,就是对一些简单运算符或者操作的封装,例如Printable:
template <typename T>
struct Printable : crtp<T, Printable>
{
static constexpr bool is_printable = true;
void print(std::ostream& os) const
{
os << this->underlying().get();
}
};
template <typename T>
struct PostIncrementable : crtp<T, PostIncrementable>
{
IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN
FLUENT_CONSTEXPR17 T operator++(int)
{
return T(this->underlying().get()++);
}
IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END
};
NamedType
是一个用于实现强类型(strong type
)的模板类,结合了多个模板参数和特性以实现灵活的功能扩展。通过对构造函数、类型转换、和技能(Skills
)进行封装,这个类的设计旨在提供一种类型安全且高效的方式来定义具有特定含义的类型。