LINUX.ORG.RU

Как правильно унаследоваться от std::variant?

 ,


0

3

Хочется сделать контейнер, что-то вроде такого:

template <int n>
struct foo {
	float v[n];
};

struct foo_holder : std::variant<foo<1>, foo<2>> {
	
	struct {/* some stuff */} info;
	
	foo_holder (int nd) {
		if (nd==1) /* foo<1> */;
		if (nd==2) /* foo<2> */;
	}
};
Где хранимый тип определяется параметрами конструктора. Никак не пойму как такое сделать правильно. Или как тут лучше быть?

★★★★★

Последнее исправление: thunar (всего исправлений: 1)

Ответ на: комментарий от intelfx

Если я правильно понимаю пожелание ТСа:

template <int n>
struct foo
{
	float v[n];
};

struct foo_holder : std::variant<foo<1>, foo<2>>
{
	
	struct {/* some stuff */} info;
	
	static auto make_base(int nd)
		-> std::variant<foo<1>, foo<2>>
	{
		if (nd == 1)
			return { foo<1>{ ... } };
		if (nd == 2)
			return { foo<2>{ ... } };
		std::unreachable();
	}

	foo_holder (int nd)
		: std::variant<foo<1>, foo<2>>(make_base(nd))
	{
	}
};
intelfx ★★★★★
()

Как правильно унаследоваться от std::variant?

унаследоваться

Никак. Правильно использовать композицию/агрегирование.

anonymous
()
Ответ на: комментарий от zx_gamer

Но по-моему это очередной STL-велосипед. Что мешает просто использовать union?

Мешает желание избавиться от рутины. Например, такой, как вызов деструктора хранимого объекта вручную в момент его разрушения, реализации аналога std::visit и т.п.

m0rph ★★★★★
()

выше уже ответили, у меня по сути такой же вариант ток чуть альтернативная имплементация:

template <int n>
struct foo
{
	float v[n];
};

using base_t = std::variant<foo<1>, foo<2>>;

struct foo_holder : base_t
{
	
	struct {/* some stuff */} info;
	

	foo_holder (int nd)
		: base_t(
		      nd == 1 ? base_t{foo<1>{}}
		    : nd == 2 ? base_t{foo<2>{}}
		    : throw std::runtime_error(std::format("invalid id: {}", nd))
	    )
	{
	}
};

peacelove
()
Ответ на: комментарий от X512

У тебя нет абсолютно никакой разницы с тем, что написал ТС.

Если у foo<1> нет дефолтного конструктора (или его по какой-то причине не хочется вызывать), и код ТСа, и твой код одинаково непригодны.

intelfx ★★★★★
()
Ответ на: комментарий от X512

код в заглавном сообщении работает «как есть».

Проблемы с ним могут возникнуть только в одном случае — когда default-initialization std::variant’а по тем или иным причинам недопустимо или невозможно.

intelfx ★★★★★
()
Ответ на: комментарий от X512

Вот такие примеры нашёл [https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2162r0.html]. Как я понимаю, обычно просто снаружи присваивают. Мне в конструкторе нужно, т.к. каждый инстанс foo кодирует численную схему (в зависимости от размерности задачи), которую потом удобно передавать в визитор, что бы для неё выбирались соответствующие функции из числодробильного бекенда, а наружу возвращался биндинг.

thunar ★★★★★
() автор топика