Я решу это для +
и +=
.
template<class D, std::size_t I, class T>
struct plus_helper {
D& operator+=( T const& rhs ) & {
using boost::get;
get<I>(self()) += rhs;
return self();
}
friend T operator+( plus_helper<D,I,T>&& self, T const& rhs ) {
using boost::get;
return get<I>(std::move(self.self())) + rhs;
}
friend T operator+( plus_helper<D,I,T>const& self, T const& rhs ) {
using boost::get;
return get<I>(self.self()) + rhs;
}
private:
D const& self() const { return *static_cast<D const*>(this); }
D & self() { return *static_cast<D*>(this); }
};
template<class D, class Indexes, class...Ts>
struct plus_helpers;
template<class D, std::size_t...Is, class...Ts>
struct plus_helpers<D, std::index_sequence<Is...>, Ts...> : plus_helper<D, Is, Ts>...
{
template<typename T>
T& get() {return boost::get<T>(self().var_);}
template<typename T>
const T& get() const {return boost::get<T>(self().var_);}
using own_type = plus_helpers<D, std::index_sequence<Is...>, Ts...>;
//using plus_helper<D,Is,Ts>::operator+...;
using plus_helper<D,Is,Ts>::operator+=...;
D& operator+=( D const& rhs )& {
using fptr = void(*)( D& lhs, D const& rhs );
// dispatch table: (or use boost::visit)
static constexpr fptr table[] = {
(+[]( D& lhs, D const& rhs ) {
using boost::get;
lhs += get<Is>(rhs);
})...
};
table[rhs.which()]( self(), rhs );
return self();
}
friend D operator+(own_type&& lhs, D const& rhs ) {
lhs += rhs;
return std::move(lhs.self());
}
friend D operator+(own_type const& lhs, D const& rhs ) {
auto tmp = lhs.self();
return std::move(tmp)+rhs;
}
private:
D& self() { return *static_cast<D*>(this); }
D const& self() const { return *static_cast<D const*>(this); }
};
это использует один бит c ++ 17 - using /*[...]*/::operator+...;
. Чтобы сделать это в c ++ 14 , вам нужно построить дерево (возможно, линейное дерево) из plus_helper
и двоичное using operator+
в каждом бутоне.
Вы, вероятно, будете иметь подобный код для каждого оператора; но не идентичны. +
и ==
- это не одно и то же, потому что вы хотите поддерживать +=
, но не ===
. ;)
Вы, вероятно, захотите несколько макросов, извергающих большую часть описанного выше шаблона.
В финальном классе мы делаем:
template<class...Ts>
class Foo:
public plus_helpers<Foo<Ts...>, std::index_sequence_for<Ts...>, Ts...>
{
boost::variant<Ts...> var_;
public:
template<std::size_t I>
friend decltype(auto) get( Foo<Ts...> const& foo ) {
using boost::get;
return get<std::tuple_element_t<I, std::tuple<Ts...>>>(foo.var_);
}
template<std::size_t I>
friend decltype(auto) get( Foo<Ts...> & foo ) {
using boost::get;
return get<std::tuple_element_t<I, std::tuple<Ts...>>>(foo.var_);
}
};
Вы можете добавить тип на основе get:
template<class T>
friend decltype(auto) get( Foo<Ts...> & foo ) {
using boost::get;
return get<T>(foo.var_);
}
template<class T>
friend decltype(auto) get( Foo<Ts...>const & foo ) {
using boost::get;
return get<T>(foo.var_);
}
также.
Живой пример .
Наивное c ++ 14 наследование / использование замены:
template<class...Bases>
struct inherit_plus_operations {}; // empty
template<class Lhs, class...Rhs>
struct inherit_plus_operations<Lhs, Rhs...>:
Lhs,
inherit_plus_operations<Rhs...>
{
//using Lhs::operator+;
//using inherit_plus_operations<Rhs...>::operator+;
using Lhs::operator+=;
using inherit_plus_operations<Rhs...>::operator+=;
};
template<class Lhs> // one
struct inherit_plus_operations<Lhs>:
Lhs
{
//using Lhs::operator+;
using Lhs::operator+=;
};
template<class D, std::size_t...Is>, class...Ts>
struct plus_helpers<D, std::index_sequence<Is...>, Ts...>:
inherit_plus_operations<plus_helper<D, Is, Ts>...>
затем избавьтесь от using /* ... */::operator+/*...*/...;
от тела.