2016-04-09 137 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