Klaus
Klaus

Reputation: 25623

why templated non const parameter constructor is preferred to given copy constructor

I want to make my class be able to be used in a std::variant.

The simply code that should work is:

int main()
{
    std::variant< int, A > v;

    A a(1);
    v = a;
}

My class contains a templated constructor:

 template <typename T> A( T& );

At this point the trouble starts! The constructor binds to the call from std::variant and not the provided A(const A&) is used anymore.

For copy&paste reasons the full example here:

#include <iostream>
#include <variant>

class A
{
    private:
        int x;

    public:

        A( A&&) {}
        A( const A& ) {}
        A(){}
        ~A() {}

        A& operator=( const A& ) { return *this;}
        A& operator=( A&& ) {return *this;}

        template <typename T>
            A( T& t  ) 
            {
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }

        A(int _x):x{_x}{}
};

int main()
{
    std::variant< int, A > v;

    A a(1);
    v = a;
}

Background:

Why the template here? The problem starts while using a constructor which takes a serializer type. The serializer can have multiple types, depends on files or streams to serialize with.

Remark: I know that the functionality of the constructors is missing!

Upvotes: 2

Views: 121

Answers (1)

Brian Bi
Brian Bi

Reputation: 119382

The problem is not with std::variant. The problem is with the constructor template,

template <typename T>
A(T& t)

Such constructors are problematic because when the argument is a non-const lvalue of type A, this constructor is preferred over the copy constructor taking const A&---which is usually not the intended behaviour. To prevent this, we usually constrain this constructor with SFINAE:

template <typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, A>>>
A(T& t)  // or T&& t

and might consider making it explicit as well.

We usually do not provide copy constructors taking non-const A&, since they are redundant next to the ones taking const A&.

Upvotes: 3

Related Questions