当前位置:网站首页>Clause 26: avoid overloading universal reference types

Clause 26: avoid overloading universal reference types

2022-06-13 04:55:00 CCSUZB

Consider the following code :

std::multiset<std::string> names;		//  Global data structure 
void logAndAdd(const std::string &name) {
    
	auto now = std::chrono::system_clock::now();
	log(now, "logAndAdd");
	names.emplace(name);				//  Add the name to the global data structure 
}

std::string petName("Darla");
logAndAdd(petName);					   //  Pass lvalue std::string
logAndAdd(std::string("Persephone"));  //  Pass the right value std::string
logAndAdd("Patty Dog");				   //  Pass the right value std::string

In the first call ,logAndAdd The formal parameter of is bound to a variable petName. stay logAndAdd Inside ,name Was passed on to names.emplace, because name It's a left value. , So it was copied into names Of .

The first 2 And the first 3 Calls name Bound to an R-value , because name It's a left value. , So it was copied into names Of ; We can rewrite logAndAdd Let it accept a universal reference :

template<typename T>
void logAndAdd(T &&name) {
    
	auto now = std::chrono::system_clock::now();
	log(now, "logAndAdd");
	names.emplace(std::forward<T>(name));
}

std::string petName("Darla");
logAndAdd(petName);					   //  Pass lvalue std::string, Copy the lvalue into multiset
logAndAdd(std::string("Persephone"));  //  Move the right value 
logAndAdd("Patty Dog");				   //  stay multiset Directly construct a std::string object , Instead of copying one st::string Temporary object of type 
}

Consider the following scenario , Let's add one logAndAdd The overloaded version of :

typename<typename T>
void logAndAdd(T &&name) {
    
	auto now = std::chrono::system_clock::now();
	log(now, "logAndAdd");
	names.emplace(std::forward<T>(name));
}

std::string nameFromIdx(int dx);
void logAndAdd(int dx) {
    
	auto now = std::chrono::system_clock::now();
	log(now, "logAndAdd");
	names.emplace(nameFromIdx(idx));				//  Add the name to the global data structure 
}

std::string petName("Darla");
logAndAdd(petName);					//  The following three usages call the formal parameter T&& The overloaded version of 
logAndAdd(std::string("Persephone"));  
logAndAdd("Patty Dog");

logAndAdd(22);						//  The formal parameter type called is int Version of 

But if the customer makes the following call , Will not compile

short nameIndx;
logAndAdd(nameIdx); // ! error 

logAndAdd There are two overloaded versions ,, The formal parameter is T&& The version of will T Derived as short, To produce an exact match . And the formal parameter is int The version of can only match after the type is promoted short Shape parameter , however names Unable to add short Element of type

One way to fill this hole is to write a constructor with perfect forwarding .

class Person{
    
public:
    template<typename T>
    explicit Person(T &&n) :name(std::forward<T>(n)){
    }
    explicit Person(int idx) : name(nameFromIdx(idx)){
    }
    Person(const Person&& rhs); 		//  The compiler generates a copy constructor 
    Person(Person &&rhs);				//  The compiler generates a move constructor 
private:
    std::string name;
};

C++ Copy constructors and move constructors will be generated by default , If the user makes the following call :

Person p("Nancy");
auto cloneOfP(p); 

The above code does not call the copy constructor , Instead, it calls the perfect forwarding constructor . This function is trying to start from a Person Object of type p Set out to initialize another Person Type of object std::string Data members of type . So compilation failed .

The perfect forwarding constructor will become more complex if the integration is involved :

class SpecialPerson : public Person
{
    
public:
    SpecialPerson(const SpecialPerson &rhs) : Person(rhs) {
    }        // copy constructor , What is called is the perfect constructor of the base class 
    SpecialPerson(SpecialPerson &&rhs) : Person(std::move(rhs)){
    }   // move constructor , What is called is the perfect constructor of the base class 
};

The final code did not compile , because std::string Not accepted SpecialPerson Type parameters

原网站

版权声明
本文为[CCSUZB]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202280518034703.html