2016-04-09 195 views
3

为什么下面的代码产生编译器错误不匹配operator*为什么我的重载乘法运算符无法识别?

template<class E> 
class vector_expression {}; 

template<class Tuple> 
class vector 
    : public vector_expression<vector<Tuple>> 
{ 
public: 
    using value_type = typename Tuple::value_type; 
}; 

namespace detail 
{ 
    template<typename T> 
    class scalar 
     : public vector_expression<scalar<T>> 
    {}; 
} 

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

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

template<class E> 
vector_binary_operation<detail::scalar<typename E::value_type>, E, std::multiplies<>> operator*(typename E::value_type value, E&& e) { 
    return { std::move(value), std::forward<E>(e), std::multiplies<>{} }; 
} 
template<class E> 
vector_binary_operation<E, detail::scalar<typename E::value_type>, std::multiplies<>> operator*(E&& e, typename E::value_type value) { 
    return { std::forward<E>(e), std::move(value), std::multiplies<>{} }; 
} 

int main() 
{ 
    vector<std::array<double, 3>> x; 
    3 * x; 

    return 0; 
} 

DEMO

+2

您的“DEMO”链接不适用于我。 –

+2

仅供参考,'3'是'int',而不是'double'。模板对这样的东西很敏感。 – Cornstalks

+0

@MartinBonner对不起,修正了这个问题。 – 0xbadf00d

回答

3

你有两个重载operator*被(暂时忽略返回类型):

template <class E> 
R operator*(typename E::value_type, E&&); 

template <class E> 
R operator*(E&&, typename E::value_type); 

在这两个情况下,一个参数是一个非推断的上下文。我们从第二次重载开始。当我们拨打3 * x时,E被推断为int,因此没有int::value_type,所以这是替代失败。

在第一次过载时,我们推导出Evector<std::array<double, 3>>&。请注意,这是参考。因此,没有E::value_type,因为它是一个引用类型。您必须首先删除该部分(对于两个重载)。最简单的方法是引入第二违约模板参数即是E引用版本:

template<class E, class ER = std::remove_reference_t<E>> 
vector_binary_operation<detail::scalar<typename ER::value_type>, ER, std::multiplies<>> 
operator*(typename ER::value_type value, E&& e); 

随着该修补程序,现在你的代码编译不能通过差异的原因:scalar没有一个构造函数。但这是一个无关的问题。

+0

''decay'缩短类型(并且它执行的额外转换是无害的) –

+0

您是对的,我刚刚注意到我忘记了写'std :: decay_t '而不是'E' – 0xbadf00d

+0

@TC它更短,但我有时候更喜欢'remove_reference',因为我们实际上只是删除了一个引用。 – Barry

1

代码失败,因为x是你不能应用::接入运营商的左值引用。为了做到这一点,你应该std::decay_t推导型E第一,即写

typename std::decay_t<E>::value_type