我正在尝试实现类似于boost / operator的功能。
这是我到目前为止所拥有的:
template<typename T, typename TAG>
struct strong_type{
explicit strong_type(T v) : v(v){}
T v;
};
template<typename T, typename TAG>
struct addition{
addition() = default;
using N = strong_type<T, TAG>;
friend N operator+(const N &a, const N &b){
return N{ a.v + b.v };
}
};
struct myint_tag{};
struct myint :
strong_type<int, myint_tag>,
addition<int, myint_tag>{
using strong_type<int, myint_tag>::strong_type;
myint(const strong_type &other) : strong_type(v){}
};
int main(){
myint a{ 2 };
myint b{ 3 };
// result is not myint, but strong_type<int, myint_tag>
myint c = a + b;
}
但是我不知道如何在没有#define的情况下实现。
是否有一种无需编写myint(const strong_type &other)
即可实现的方法?
答案 0 :(得分:1)
template<class D>
struct strong_add {
friend D operator+( D lhs, D const& rhs ) {
lhs += rhs; return lhs;
}
friend D& operator+=( D& lhs, D const& rhs ) {
lhs.v += rhs.v;
return lhs;
}
};
struct myint :
strong_type<int, myint_tag>,
strong_add<myint> {
using strong_type<int, myint_tag>::strong_type;
};
这使用CRTP。 +
按值接受lhs参数,因为如果您拥有便宜如价的昂贵复制型,例如std::string
:
a + b + c + d + e
加上朴素的const&, const&
,我们在每个+
处得到一个副本,因为我们在操作员的每个返回点处创建了一个全新的对象。
加上value, const&
,将复制第一个a
。然后我们进行+= b
,然后移动结果,然后+= c
然后移动结果,然后+= e
然后移动结果。仅制作一份。
如果您愿意,我们可以走得更远。
首先,我们这样做:
template<class T>
class detect_strong_type {
template<class X, class Tag>
static std::true_type tester( strong_type<X, Tag>const* );
static std::false_type tester( void* );
public:
using type=decltype( tester( (T*)nullptr ) );
};
template<class T>
using is_strong_type = typename detect_strong_type<T>::type;
enum class operators {
add, subtract, multiply, divide
};
template<operators o>
using op_tag_t = std::integral_constant<operators, o>;
template<operators o>
constexpr op_tag_t<o> op_tag{};
auto default_op( op_tag_t<operators::add> ) { return [](auto& lhs, auto const& rhs){ lhs += rhs; }; }
auto default_op( op_tag_t<operators::subtract> ) { return [](auto& lhs, auto const& rhs){ lhs -= rhs; }; }
auto default_op( op_tag_t<operators::multiply> ) { return [](auto& lhs, auto const& rhs){ lhs *= rhs; }; }
auto default_op( op_tag_t<operators::divide> ) { return [](auto& lhs, auto const& rhs){ lhs /= rhs; }; }
template<operators op, class D, class...Skip>
void do_operator( op_tag_t<op>, D& lhs, D const& rhs, Skip&&... ) {
default_op( op_tag<op> )( lhs, rhs );
}
template<class D>
struct can_add {
friend D operator+( D lhs, D const& rhs ) {
lhs += rhs; return lhs;
}
friend D& operator+=( D& lhs, D const& rhs ) {
do_operator( op_tag<operators::add>, lhs, rhs );
return lhs;
}
};
template<class D>
struct can_subtract {
friend D operator-( D lhs, D const& rhs ) {
lhs -= rhs; return lhs;
}
friend D& operator-=( D& lhs, D const& rhs ) {
do_operator( op_tag<operators::subtract>, lhs, rhs );
return lhs;
}
};
template<class D>
struct can_multiply {
friend D operator*( D lhs, D const& rhs ) {
lhs *= rhs; return lhs;
}
friend D& operator*=( D& lhs, D const& rhs ) {
do_operator( op_tag<operators::multiply>, lhs, rhs );
return lhs;
}
};
template<class D>
struct can_divide {
friend D operator/( D lhs, D const& rhs ) {
lhs *= rhs; return lhs;
}
friend D& operator/=( D& lhs, D const& rhs ) {
do_operator( op_tag<operators::divide>, lhs, rhs );
return lhs;
}
};
template<class D>
struct can_math:
can_add<D>, can_multiply<D>, can_subtract<D>, can_divide<D>
{};
现在我们向do_operator
讲解strong_type
:
template<operators op, class D,
std::enable_if_t< is_strong_type<D>{}, bool> =true
>
void do_operator( op_tag_t<op>, D& lhs, D const& rhs ) {
do_operator( op_tag<op>, lhs.v, rhs.v );
}
这有效:
struct myint :
strong_type<int, myint_tag>,
can_math<myint>
{
using strong_type<int, myint_tag>::strong_type;
};
int main(){
myint a{ 2 };
myint b{ 3 };
myint c = a*b + b - a;
}
现在,仅对于强大的操作人员而言,这有点过头了。它可以让您做的是:
struct some_type: can_add<some_type> {
std::vector<int> values;
friend void do_operator( op_tag_t<operators::add>, some_type& lhs, some_type const& rhs ) {
lhs.values.insert( lhs.values.end(), rhs.values.begin(), rhs.values.end() );
}
};
,现在实现了some_type + some_type
和some_type += some_type
。
答案 1 :(得分:0)
Y牛-亚当·内夫罗蒙特绝对非常好,
但是我发现更简单明了的方法。
如果您稍作思考,所有这些addition
/ strong_add
类都需要注入“全局”运算符。
运算符本身不需要成为朋友,但是使用friend
关键字,否则运算符将不会被注入“全局”空间。
也没有人需要该结构。它仅用于注入运算符,因此它可能是空结构。
template<typename T, typename TAG>
struct strong_type{
using type = T;
T v;
explicit constexpr strong_type(const T &v) : v(v) {}
};
然后令人惊讶:
template<class V>
struct arithmetic{
friend constexpr V operator+ (const V &a, const V &b){ return { a.v + b.v }; }
friend constexpr V operator- (const V &a, const V &b){ return { a.v - b.v }; }
friend constexpr V operator* (const V &a, const V &b){ return { a.v * b.v }; }
friend constexpr V operator/ (const V &a, const V &b){ return { a.v / b.v }; }
friend V &operator+=(V &a, const V &b){ a.v += b.v; return a; }
friend V &operator-=(V &a, const V &b){ a.v -= b.v; return a; }
friend V &operator*=(V &a, const V &b){ a.v *= b.v; return a; }
friend V &operator/=(V &a, const V &b){ a.v /= b.v; return a; }
};
最后:
struct myint_tag{};
struct myint : strong_type<int, myint_tag>,
arithmetic <myint>
{
using strong_type::strong_type;
};
int main(){
constexpr myint a{ 2 };
constexpr myint b{ 3 };
myint x{ 3 };
myint y{ 5 };
x = x + y * x;
}