简体   繁体   中英

Why delete of templete copy constructor cause assignment operator disfunctional?

I have code like below which looks a little bit Confusing. I define a template class. It has a user-defined constructor. When I declare two objects of this template class by "operator =", its user-defined contructor is called to my surprise. Besides, After deleting its copy constructor, the compiling cannot even pass during resolution of "operator =". Does templete constructors have different rules than non-templete class?

#include "iostream"
using namespace std;

template <typename T>
class MyPtr
{
private:
    T p_;
public:
    MyPtr(T P = NULL): p_(P)
    {
        cout<<"track!!"<<endl;
    }

    //MyPtr(const MyPtr<T> & P) = delete;
    ~MyPtr()
    {
 
    }
};

int main()
{
    int i=3;
    int j=4;
    MyPtr<int> p = i;
    MyPtr<int> pp = j;
}

Does templete constructors have different rules than non-templete class?

No.

MyPtr<int> p = i; (and MyPtr<int> pp = j; ) is copy initialization . Note that this is initialization but not assignment , as the effect p is initialized by the constructor MyPtr::MyPtr(T) . eg

MyPtr<int> p = i; // initialization; constructors get called
p = j;            // assignment; assignment operators (operator=) get called

Before C++17, i would be converted to MyPtr<int> via MyPtr::MyPtr(T) firstly, then the conversion result, ie the temporary MyPtr<int> is copied/moved to initialize p ; even the copy/move operation is allowd to be optimized, the copy/move constructor is required to be accessible. Declaring copy constructor as delete makes copy constructor unusable and move constructor won't be generated, thus makes MyPtr<int> p = i; ill-formed until C++17.

Since C++17 the optimization is mandatory and the copy/move constructor is not required to be accessible again, that means your code would compile fine with C++17 mode even declaring copy constructor as delete .

  • If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary (until C++17) prvalue expression (since C++17) if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM