2016-03-28 137 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成员)的左侧参数。为什么会发生?

让我们解析:

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

thisconst成员函数将A<T> const* const。取消参考,给我们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

单独确定(返回从'lhs'隐式移动)。在一行中不是(因为当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; 
相关问题