Я хочу, чтобы мой класс можно было использовать в 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;
}
Фон:
Почему шаблон здесь?
Проблема начинается при использовании конструктора, который принимает тип сериализатора. Сериализатор может иметь несколько типов, в зависимости от файлов или потоков для сериализации.
Замечание: я знаю, что функциональность конструкторов отсутствует!
Проблема не с 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&
,
Других решений пока нет …