2016-03-28 30 views
1

として使用し、私は単純なクラスがあります。推定されるタイプ*これはテンプレート関数テンプレート引数

#include <utility> 

template<class T, class... Ts> 
T make(const Ts&... args) //generic class maker 
{ 
    return T(args...); 
} 

template<class T> 
class A 
{ 
public: 
    A(void)   : x_(T()), y_(T()) {} 
    explicit A(int x) : x_(x), y_(x) {} 
    A(int x, int y) : x_(x), y_(y) {} 
    A(const A& other) : x_(other.x_), y_(other.y_) {} 
    A(A&& temp)  : x_(std::move(temp.x_)), y_(std::move(temp.y_)) {} 

    auto& operator =(A other); 
    auto& operator +=(const A& other); 
    auto operator + (const A& other) const; 
private: 
    T x_; 
    T y_; 
}; 

template<class T> 
auto& A<T>::operator =(A<T> other) 
{ 
    std::swap(*this, other); return *this; 
} 

template<class T> 
auto& A<T>::operator+=(const A<T>& other) 
{ 
    x_ += other.x_; 
    y_ += other.y_; 
    return *this; 
} 

template<class T> 
auto A<T>::operator+(const A<T>& other) const 
{ 
    return make<A<T>>(*this) += other; 
} 

int main() 
{ 
    A<int> first(1); 
    auto second = A<int>(2,2); 
    auto third = make<A<int>>(second+first); 
    auto fourth = make<A<int>>(4); 
    auto fifth = make<A<int>>(5,5); 
} 

をしかし、私は*このことから演算子+タイプを推測しようとすると、私は期待していない奇妙なエラーが発生します:

template<class T> 
auto A<T>::operator+(const A<T>& other) const 
{ 
    return make<typename std::remove_cv<decltype(*this)>::type>(*this) += other; 
} 

int main() 
{ 
    auto solo = A<int>(); 
    solo + solo; 
} 

エラー:

error: passing 'const A<int>' as 'this' argument of 'auto& A<T>::operator+=(const A<T>&) 
[with T = int]' discards qualifiers [-fpermissive] 
    return make<typename std::remove_cv<decltype(*this)>::type>(*this) += other; 
                     ^
error: use of 'auto& A<T>::operator+=(const A<T>&) [with T = int]' before deduction 
of 'auto' 
error: invalid use of 'auto' 
    return make<typename std::remove_cv<decltype(*this)>::type>(*this) += other; 
                     ^
error: invalid use of 'auto' 

私が正しい場合は、make(...)は、新しいオブジェクトを作成する必要があります(これはcvから解放されるはずです)、なぜdiscards qualifiers [-fpermissive]にエラーがありますか?

答えて

3

constオブジェクトをoperator+=の左辺の引数として渡しています(これはconstのメンバーではありません)。なぜそれが起こっているのですか?

さんが解析してみましょう:constメンバ関数のための

typename std::remove_cv<decltype(*this)>::type 

thisA<T> const* constになります。 DereferencingはA<T> const&A<T> constではありません!)を返します。しかし参考文献にはcv -qualificationsが含まれていないので、remove_cvは実際に何もしません。その結果、上記のタイプがある:

A<T> const& 

あなたはまったく望んでいたものではありません。 thisのコピーを作成し、constへの参照をthisにバインドしませんでした。代わりに行うべきことは、参照を削除することです。

typename std::decay<decltype(*this)>::type 

だから、あなたが何をしたいです:

template<class T> 
auto A<T>::operator+(const A<T>& other) const 
{ 
    return make<std::decay_t<decltype(*this)>>(*this) += other; 
} 

をしかし、それは恐ろしく複雑だそこ型特性はそのためです。私は次のようなものを好むでしょう:

template <class T> 
class A { 
    ... 
    friend A<T> operator+(A lhs, A const& rhs) { 
     lhs += rhs; 
     return lhs; 
    } 
}; 
+0

'return lhs + = rhs;'典型的な '+ ='与えられたコピーはかなりひどいです。 –

+0

@ T.C。別途返品してください。しかし、私たちは無関係にコピーを作成しています。これが良い方法でない場合は、[この回答](http://stackoverflow.com/a/4421719/2069064)を修正したいですか? – Barry

+0

これとは別にOKです(リターンは暗黙的に 'lhs'から移動します)。 'lhs + = rhs'が左辺値であるとき、通常は' lhs + = rhs'が 'lhs' *をもう一度コピーします。 –

2

*this式であるので、decltypeで照会すると、それはと呼ばれるタイプに適用されるべきであるstd::remove_cv形質は、参照型に適用されていることをので、左辺値参照型を生じ、そして:

return make<typename std::remove_cv< 
       typename std::remove_reference<decltype(*this)>::type 
      >::type>(*this) += other; 
関連する問題