jaw
jaw

Reputation: 510

Perfect forwarding for methods of non-template classes

Perfect forwarding is usually seen in the context of template classes. For a non-template class, is it worth making e.g. the constructor a template method so it can use perfect forwarding? Something like the below:

class Foo()
{
    public:
        template<typename T>
        Foo(T &&vec) : memberVec(std::forward<T>(vec)) {};

    private:
        std::vector memberVec;
};

The advantages are fundamentally the same, but is anything different when we know the real class type? When would this be good practice and when not?

Upvotes: 4

Views: 432

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275260

A non-explicit one-argument ctor is a converting ctor. Unless Foo should be convertible-from a vector (which might be true), you should make it explicit.

In general, with one-argument ctors you need to SFINAE-disable Foo types from being matched. The implicit Foo&& and Foo const& ctors are worse matches when you invoke Foo with a Foo& (say, an non-const lvalue) than your template ctor. A simple class=std::enable_if_t<!std::is_same<std::decay_t<T>,Foo>> suffices.

Slightly more code will be generated.

In this case, std::vector<X> is ridiculously cheap to move, so

Foo( std::vector<X> vec ):memberVec(std::move(vec)) {}

is 99% as efficient and clearer.

The usual perfect forwarding failures apply when you use it. The above example doesn't have them -- I can Foo x({1,2,3}) and it passes {1,2,3} to construct the vec. With T&& it won't, because it cannot deduce what T is.

Upvotes: 5

Related Questions