samedi 8 août 2020

Derived class member functions are involved

I got a piece of code from the C++ Templates the Complete Guide book: In the following program, we create a Person class with perfect forwarded template constructor and two other member function (const copy constructor , move constructor)

#include <utility>
#include <string>
#include <iostream>

class Person
{
  private:
    std::string name;
  public:
    // generic constructor for passed initial name:
    template<typename STR>
    explicit Person(STR&& n) : name(std::forward<STR>(n)) {
        std::cout << "TMPL-CONSTR for '" << name << "'\n";
    }

    // copy and move constructor:
    Person (Person& p) : name(p.name) {
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    }
    Person (Person const& p) : name(p.name) {
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    }
    Person (Person&& p) : name(std::move(p.name)) {
        std::cout << "MOVE-CONSTR Person '" << name << "'\n";
    }
};


int main()
{
  std::string s = "sname";
  Person p1(s);
  Person p2("tmp");
  Person p3(p1);            // Error
  Person p4(std::move(p1));
}

Regarding the error at line Person p3(p1); Here the book says "According to overload resolution rules"

template<typename STR>
Person(STR&& n)

"is better match than the copy constructor"

Person(const Person& p)

So, if I add one more constructor inside Person as follows:

Person (Person& p) : name(p.name) {
    std::cout << "COPY-CONSTR Person '" << name << "'\n";
}

The error should go away. Indeed the error went away and here is the output:

TMPL-CONSTR for 'sname'
TMPL-CONSTR for 'tmp'
COPY-CONSTR Person 'sname'              : this is due to `Person (Person& p)`
MOVE-CONSTR Person 'sname'

But the book also says, this is a partial solution only, because template constructor of Derived class of Person is still a better match by the overload resolution rules.

So I tried to check that also:

#include <utility>
#include <string>
#include <iostream>

class Person
{
  private:
    std::string name;
  public:
    // generic constructor for passed initial name:
    template<typename STR>
    explicit Person(STR&& n) : name(std::forward<STR>(n)) {
        std::cout << "TMPL-CONSTR for '" << name << "'\n";
    }

    // copy and move constructor:
    Person (Person& p) : name(p.name) {
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    }
    Person (Person const& p) : name(p.name) {
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    }
    Person (Person&& p) : name(std::move(p.name)) {
        std::cout << "MOVE-CONSTR Person '" << name << "'\n";
    }
};

#if 1 // or 0
class newPerson : public Person
{
  private:
    std::string name;
  public:
    // generic constructor for passed initial name:
    template<typename STR>
    explicit newPerson(STR&& n) : name(std::forward<STR>(n)) {
        std::cout << "TMPL-CONSTR for '" << name << "'\n";
    }

    // copy and move constructor:
    newPerson (newPerson const& p) : name(p.name) {
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    }
    newPerson (newPerson&& p) : name(std::move(p.name)) {
        std::cout << "MOVE-CONSTR Person '" << name << "'\n";
    }
};
#endif

int main()
{
  std::string s = "sname";
  Person p1(s);
  Person p2("tmp");
  Person p3(p1);             // Error again
  Person p4(std::move(p1));
}

I am pasting the clang error in this case (gcc error list were too big)

specialmemtmplMain.cpp:41:5: error: constructor for 'newPerson' must explicitly initialize the base class 'Person' which does not have a default constructor
    newPerson (newPerson const& p) : name(p.name) {
    ^
specialmemtmplMain.cpp:5:7: note: 'Person' declared here
class Person
      ^
specialmemtmplMain.cpp:44:5: error: constructor for 'newPerson' must explicitly initialize the base class 'Person' which does not have a default constructor
    newPerson (newPerson&& p) : name(std::move(p.name)) {
    ^
specialmemtmplMain.cpp:5:7: note: 'Person' declared here
class Person
      ^
2 errors generated.

So, my question is, I have not instantiated anything of newPerson class. Then why is the error refers to newPerson constructors ? What is really going on here ?

Aucun commentaire:

Enregistrer un commentaire