почему шаблонный неконстантный конструктор параметров предпочтительнее данного конструктора копирования - PullRequest
0 голосов
/ 25 августа 2018

Я хочу, чтобы мой класс можно было использовать в std::variant.

Простой код, который должен работать:

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

    A a(1);
    v = a;
}

Мой класс содержит шаблонный конструктор:

 template <typename T> A( T& );

На этом этапе проблема начинается! Конструктор привязывается к вызову с std::variant, и больше не используется A(const A&).

По причинам копирования и вставки полный пример здесь:

#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;
}

Справочная информация:

Почему шаблон здесь? Проблема начинается при использовании конструктора, который принимает тип сериализатора. Сериализатор может иметь несколько типов, в зависимости от файлов или потоков для сериализации.

Примечание: я знаю, что функциональность конструкторов отсутствует!

1 Ответ

0 голосов
/ 25 августа 2018

Проблема не с std::variant.Проблема заключается в шаблоне конструктора,

template <typename T>
A(T& t)

Такие конструкторы проблематичны, потому что, когда аргумент не является const lvalue типа A, этот конструктор предпочтительнее, чем конструктор копирования, принимающий const A& --- что обычно не является предполагаемым поведением.Чтобы предотвратить это, мы обычно ограничиваем этот конструктор с помощью SFINAE:

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

и можем также рассмотреть возможность сделать его explicit.

Обычно мы не предоставляем конструкторы копирования, принимающие не const A&, поскольку они избыточны рядом с теми, которые принимают const A&.

...