C ++ 11 dedicated "proxy constructors" delegation to private generic link builder?

Considering Scott Meyer's book, Effective Modern C ++, paragraph 24 (and later) and paragraph 41, I am curious that this book contradicts:

  • individual constructors for lvalue and rvalue parameters

to

  1. generic universal design solution

It says that 1. has the disadvantage of duplicating code.
While 2. has a flaw potentially used for unwanted types.

I wonder why the book does not mention a mixed model , as in the code example below.

It uses specialized constructors with type support for lvalue and rvalue, but it delegates one (private) common implementation for a "universal reference". This avoids the unwanted template types of the public universal link constructor.

So, is there something wrong with the approach below? Did I miss something?

    #include <iostream>
    #include <string>

    class MyClass
    {
    private:

        enum class Dummy { Nop = 0 } ;

        template <class T>
        MyClass(Dummy, T&& data)
        : _data(std::forward<T>(data))
        {
            std::cout << "MyClass universal reference template c'tor" << std::endl;
        }

    public:

        // proxy c'tors delegating to universal reference c'tor
        MyClass (std::string const & data)
        : MyClass(Dummy::Nop, data)
        {
            std::cout << "MyClass lvalue c'tor" << std::endl;
        }

        MyClass (std::string && data)
        : MyClass(Dummy::Nop, std::move(data))
        {
            std::cout << "MyClass rvalue c'tor" << std::endl;
        }

    private:
        std::string _data;
    };

    int main(int, char**)
    {

        {
            std::string str("demo");
            MyClass myClass(str);
        }

        {
            MyClass myClass("hello, world");
        }

        return 0;
    }
+2
source share
1 answer

Now let's drop the book and do it right:

Pros:

  • Optimum performance

  • Type restrictions fixed

  • DRY

Minuses:

  • None

-

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

class MyClass
{

public:

    template <class T, std::enable_if_t<std::is_constructible<std::string, T>::value>* = nullptr>
    MyClass(T&& data)
    : _data(std::forward<T>(data))
    {
        std::cout << "MyClass universal reference template c'tor" << std::endl;
    }

private:

    std::string _data;

};

int main()
{
    using namespace std::string_literals;

    auto a = MyClass("hello"s);
    auto b = MyClass("world");


    const auto s = "Hello, World"s;
    auto s2 = "Hello, World";

    auto c = MyClass(s);
    auto d = MyClass(s2);

// won't compile
//    auto e = MyClass(10);

}
0
source

All Articles