2016-04-09 19 views
3

Aşağıdaki kod neden derleyicisi hatası veriyor operator*?Aşırı yüklenmiş çoğaltma operatörüm neden tanınmadı?

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" bağlantınız benim için çalışmıyor. –

+2

FYI, '3' bir' int', 'double' değil. Şablonlar bu gibi şeylere karşı hassastır. – Cornstalks

+0

@MartinBonner Üzgünüz, bunu düzeltin. – 0xbadf00d

cevap

3

yazma çıkarılabilir tip std::decay_t gerekir Vakalar, bir argüman çıkarsayan bir bağlamdır. 2. aşırı yüklenmeyle başlayalım. 3 * x ile aradığımız zaman, E, int olarak çıkarılır, int::value_type yoktur, bu bir değiştirme hatasıdır.

İlk aşırı yüklemede, E'u vector<std::array<double, 3>>& olarak anıyoruz. Bir referansı olduğunu unutmayın. Bu nedenle, bir referans türü olduğundan E::value_type yoktur. Önce bu parçayı kaldırmalısınız (her iki aşırı yüklenme için). En basit yolu E bir un başvurulan sürümüdür ikinci temerrüde şablon argümanı tanıtmaktır: scalar bir kurucu olmamasından:

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); 

o düzeltmeyi hemen şimdi kod fark nedenle derleme değil . Ama bu ilgisiz bir problem.

+0

'çürüme 'daha kısa yazıyor (ve gerçekleştirdiği ek dönüşümler zararsızdır) –

+0

Haklısın, sadece unuttuğumu fark ettim "E" yerine std :: decay_t 'yazın. – 0xbadf00d

+0

@TC Bu daha kısadır, ancak bazen bir referansı çıkardığımız netlik için remove_reference özelliğini tercih ederim. – Barry

1

x Eğer :: erişim operatörünü uygulayamaz hangi bir lvalue referans olduğu için kod başarısız olur. ikisinde de

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

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

: Bunu yapmak için, size iki (an için dönüş türü görmezden) olan operator* aşırı olması E ilk, yani

typename std::decay_t<E>::value_type 
İlgili konular