重载一组类的加上运算符

时间:2016-04-08 19:58:56

标签: c++ operator-overloading c++14 typetraits c++17

请考虑以下代码段:

template<class E>
class vector_expression
{};

template<class Tuple>
class vector
    : public vector_expression<vector<Tuple>>
{};

template<class E1, class E2, class BinaryOperation>
class vector_binary_operation
    : public vector_expression<vector_binary_operation<E1, E2, BinaryOperation>>
{
public:
    vector_binary_operation(E1&& e1, E2&& e2, BinaryOperation op)
        : m_e1(e1), m_e2(e2),
          m_op(op)
    {}

private:
    E1 m_e1;
    E2 m_e2;
    BinaryOperation m_op;
};

template<class E1, class E2>
vector_binary_operation<E1, E2, std::plus<>> operator+(E1&& e1, E2&& e2) {
    return{ std::forward<E1>(e1), std::forward<E2>(e2), std::plus<>{} };
}

上面的代码确保vector_binary_operation存储对命名对象的引用,并为临时对象创建副本。问题是operator+的接口,因为它实际上为任何类型定义了此运算符。如果我想保留功能,但只需要为vector_expression中的类型定义运算符,我需要更改什么?

2 个答案:

答案 0 :(得分:2)

您可以通过以下方式使用SFINAE和IFERROR

std::is_base_of

Live Demo

答案 1 :(得分:1)

@ 101010已经给出了原则。当我在answers之一的评论中提出这个问题时,我正在扩展它。

因为我猜你的运算符比operator+多,所以编写一个traits类很方便,它检查所有传递的类型是否都是vector_expression

template<typename ... Ts> struct is_vector_expression 
     : public std::false_type {};
template<typename T> struct is_vector_expression<T>
     : public std::is_base_of<vector_expression<std::decay_t<T> >, std::decay_t<T> >::type {};
template<typename T, typename ... Ts> struct is_vector_expression<T, Ts ...>
     : public std::integral_constant<bool, is_vector_expression<T>::value
                                        && is_vector_expression<Ts ...>::value> {};

使用C ++ 17时,您也可以跳过可变参数模板并使用std::conjunction

接下来,您可以将其包装在合适的别名中,这样您就不必一直写std::enable_if_t

template<typename ... Ts>
using enable_for_vector_expression = std::enable_if_t<is_vector_expression<Ts...>::value>;

最后,对于所有重载运算符,您可以在以下示例中使用它:

template<typename E1, typename E2,
         typename = enable_for_vector_expression<E1, E2> >
auto operator+(E1&& e1, E2&& e2)
{
    //...
}