使用 C++ 概念实现强类型的特征
Implementing traits for strong types with C++ concepts
我希望有一个很好的方法来启用我的强类型(例如 StockPrice、Count)的功能(例如 ++、*=、/)。
我不喜欢为此使用继承 (CRTP/mixins),我知道有些人可能会喜欢它,但我不想在这个用例中使用继承。
所以我有这样的代码 this:
template<class, template<class...> class>
inline constexpr bool is_specialization = false;
template<template<class...> class T, class... Args>
inline constexpr bool is_specialization<T<Args...>, T> = true;
template<typename Underlying, typename TagType>
struct StrongT{
Underlying val;
using Tag = TagType;
};
template<typename T>
concept addable = is_specialization<T, StrongT> && requires (T& t){
typename T::Tag::addable_trait;
};
struct IndexTag{
using addable_trait = int;
};
using Index = StrongT<size_t, IndexTag>;
struct NanosTag{
using addable_trait = int;
};
using Nanos = StrongT<size_t, struct NanosTag>;
template<addable T>
T operator + (const T& a, const T& b){
return T{a.val+b.val};
}
我喜欢它,因为我可以在标签结构中列出我的“特征”,但我不喜欢它,因为它有点垃圾。我不能像这样内联声明标签结构:
using Nanos = StrongT<size_t, struct NanosTag{/*...*/}>;
那么有没有办法在不使用继承的情况下以更短的方式完成我想做的事情?
注意:我这里只有一个trait/concept,显然我想要支持很多特性,例如comparable/incrementable...
如果我对您的理解正确,您正在寻找一种方法来确保甚至以编程方式强制执行 class 无需继承即可实现某些功能。一种可能的方法是创建一个需要此功能的 concept
,然后使用 static_assert
验证有问题的 class 是否提供了该功能。
示例:
假设我们想要一个具有 ++
和 --
运算符的 class 我们必须声明这样一个概念:
template<typename T>
concept ExpectedTraits = requires(T t) {
t++;
t--;
};
然后如果我们想断言(例如)class Object
具有所需的特征,我们需要断言它 -
static_assert(ExpectedTraits<Object>);
如果 class Object
不支持 ++
和 --
,则此断言将失败并且代码将无法编译,直到 Object
支持这些操作数。
怎么样
// Different capability tags
struct Addable{};
struct PreIncrementable{};
// ...
template <typename Underlying,
typename TagType,
typename... CapabilityTags>
struct StrongT
{
Underlying val;
using Tag = TagType;
friend StrongT operator+(const StrongT& lhs, const StrongT& rhs)
requires((std::is_same_v<Addable, CapabilityTags> || ...))
{
return T{lhs.val + rhs.val};
}
StrongT& operator++()
requires((std::is_same_v<PreIncrementable, CapabilityTags> || ...))
{
++val;
return *this;
}
//...
};
然后
struct NanosTag;
using Nanos = StrongT<size_t, NanosTag, Addable /*, ..*/>;
我希望有一个很好的方法来启用我的强类型(例如 StockPrice、Count)的功能(例如 ++、*=、/)。
我不喜欢为此使用继承 (CRTP/mixins),我知道有些人可能会喜欢它,但我不想在这个用例中使用继承。
所以我有这样的代码 this:
template<class, template<class...> class>
inline constexpr bool is_specialization = false;
template<template<class...> class T, class... Args>
inline constexpr bool is_specialization<T<Args...>, T> = true;
template<typename Underlying, typename TagType>
struct StrongT{
Underlying val;
using Tag = TagType;
};
template<typename T>
concept addable = is_specialization<T, StrongT> && requires (T& t){
typename T::Tag::addable_trait;
};
struct IndexTag{
using addable_trait = int;
};
using Index = StrongT<size_t, IndexTag>;
struct NanosTag{
using addable_trait = int;
};
using Nanos = StrongT<size_t, struct NanosTag>;
template<addable T>
T operator + (const T& a, const T& b){
return T{a.val+b.val};
}
我喜欢它,因为我可以在标签结构中列出我的“特征”,但我不喜欢它,因为它有点垃圾。我不能像这样内联声明标签结构:
using Nanos = StrongT<size_t, struct NanosTag{/*...*/}>;
那么有没有办法在不使用继承的情况下以更短的方式完成我想做的事情?
注意:我这里只有一个trait/concept,显然我想要支持很多特性,例如comparable/incrementable...
如果我对您的理解正确,您正在寻找一种方法来确保甚至以编程方式强制执行 class 无需继承即可实现某些功能。一种可能的方法是创建一个需要此功能的 concept
,然后使用 static_assert
验证有问题的 class 是否提供了该功能。
示例:
假设我们想要一个具有 ++
和 --
运算符的 class 我们必须声明这样一个概念:
template<typename T>
concept ExpectedTraits = requires(T t) {
t++;
t--;
};
然后如果我们想断言(例如)class Object
具有所需的特征,我们需要断言它 -
static_assert(ExpectedTraits<Object>);
如果 class Object
不支持 ++
和 --
,则此断言将失败并且代码将无法编译,直到 Object
支持这些操作数。
怎么样
// Different capability tags
struct Addable{};
struct PreIncrementable{};
// ...
template <typename Underlying,
typename TagType,
typename... CapabilityTags>
struct StrongT
{
Underlying val;
using Tag = TagType;
friend StrongT operator+(const StrongT& lhs, const StrongT& rhs)
requires((std::is_same_v<Addable, CapabilityTags> || ...))
{
return T{lhs.val + rhs.val};
}
StrongT& operator++()
requires((std::is_same_v<PreIncrementable, CapabilityTags> || ...))
{
++val;
return *this;
}
//...
};
然后
struct NanosTag;
using Nanos = StrongT<size_t, NanosTag, Addable /*, ..*/>;