其他分享
首页 > 其他分享> > 模板的完美转发

模板的完美转发

作者:互联网

 

模板的完美转发

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


template <class T, class U>
concept Derived = std::is_base_of<T, U>::value;

template <class T, class U>
concept NoDerived = !Derived<T, U>;

class Person
{
private:
    std::string name;
public:


    
    // generic constructor for passed initial name:
    // template<typename STR>
    // Person(STR&& n) : name(std::forward<STR>(n)) {
    //     std::cout << "TMPL-CONSTR for '" << name << "'\n";
    // }
    template<typename STR>
    //requires std::integral_constant<bool, !std::is_base_of_v<Person, std::decay_t<STR>>>
    //requires std::is_base_of_v<Person, std::decay_t<STR>>
    requires NoDerived<Person, std::decay_t<STR>>
    //requires std::is_convertible_v<STR, std::string>  
    Person(STR&& n) : name(std::forward<STR>(n)) {
        std::cout << "TMPL-CONSTR for '" << name << "'\n";
    }
    
    // template<typename STR, typename = std::enable_if_t < !std::is_base_of_v<Person, std::decay_t<STR>>>>
    // Person(STR && n) : name(std::forward<STR>(n)) {
    //     std::cout << "TMPL-CONSTR for '" << name << "'\n";
    // }
    // copy and move constructor:
    Person(Person const& p) : name(p.name) {
        std::cout << "COPY-CONSTR Person '" << name << "'\n";
    }
    Person(Person&& p) noexcept : name(std::move(p.name)) {
        std::cout << "MOVE-CONSTR Person '" << name << "'\n";
    }
};

class SpecialPerson : public Person
{
public:
    using Person::Person; //继承构造函数

    //以下两个函数会从父类继承过来,因此无需手动实现。但为了看清楚其声明,特重新
    //罗列出来:

    //拷贝构造函数
    //由于sp的类型为SpecialPerson。当调用Person(sp)时,完美构造函数会产生更精确的匹配
    //Person(const SpecialPerson&),在这个构造函数中string类型的name成员用子类SpecialPerson
    //对象初始化,显然会编译失败。注意这里Person的构造函数
    //SpecialPerson(const SpecialPerson& sp) : Person(sp) {}  

    //移动构造函数
    //SpecialPerson(SpecialPerson&& sp) noexcept: Person(std::move(sp)) {}
};


int main() {
    std::string s = "sname";
    Person p1(s); //用string对象初始化 => 调用Person(const string&)

    //1. 完美构造函数产生更精确的匹配:
    Person p2(p1); //error,完美转发构造函数会产生更加精确的匹配Person(Person&),但是在
                     //该函数中,当初始化name时会执行name(std::forward<Person>(p1)),由于
                     //name是std::string类型,并不没有提供这样一个通过Person对象来初始化
                     //的构造函数,因此编译失败。

    //2. Person子类的拷贝构造和移动构造:
    //由于子类构造时,通过Person(sp)/Person(std::move(sp)调用了父类构造函数,此时父类的造
    //完美转发函数中将产生一个匹配的构造函数。而在这个函数中会用子类SpecialPerson对象来
    //初始化std::string类型的name对象,这显然也是不能通过的。
    SpecialPerson sp("spname");
    SpecialPerson sp1(sp);
    SpecialPerson sp2(std::move(sp));

    //3.解决方案:就是有条件禁用父类的完美转发构造函数。即当通过Person及其子类对象创建
    //对象时,不调用完美转发构造函数,而是转为调用普通的拷贝构造或移动构造函数。
    //如将Person的完美构造函数声明为:
    //template<typename STR, typename = std::enable_if_t < !std::is_base_of_v<Person, std::decay_t<STR>>>>
    //Person(STR && n) : name(std::forward<STR>(n)) {
    //    std::cout << "TMPL-CONSTR for '" << name << "'\n";
    //}
   
    return 0;
}

 

标签:std,name,完美,sp,Person,转发,模板,构造函数
来源: https://www.cnblogs.com/smartptr/p/16159467.html