请考虑以下代码段:
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
中的类型定义运算符,我需要更改什么?
答案 0 :(得分:2)
答案 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)
{
//...
}