Можно ли автоматически извлечь тип из дискриминационного объединения?

Можно ли извлечь тип различенного объединения для инициализации «автоматической» переменной? Достаточно просто, если вы передаете тип в шаблон, но я бы хотел что-то «авто». Было бы здорово использовать решение с использованием функции посетителя или ограниченного списка типов (например, mpl :: vector).

Пример показан ниже:

#include <iostream>
#include <typeindex>
#include <cassert>

struct d_union {
template <typename T>
d_union(T t) {
*reinterpret_cast<T*>(data) = t;
_type_id = &typeid(T);
}

template <typename T>
const T* get_pointer() const {
if (_type_id == &typeid(T))
return reinterpret_cast<const T*>(data);
else
return nullptr;
}

template <typename T>
const T get() const {
assert (_type_id == &typeid(T));
return *get_pointer<T>();
}

alignas(8) char data[8];
const std::type_info *_type_id;
};std::ostream& operator<<(std::ostream&os, const d_union &u) {
if (auto ip = u.get_pointer<int>())
os << *ip;
if (auto fp = u.get_pointer<float>())
os << *fp;
return os;
}

int main() {

d_union _i = d_union(42);
d_union _f = d_union(3.14f);

std::cout << "d_union(42) = "   << _i << std::endl;
std::cout << "d_union(3.14) = " << _f << std::endl;

int _get_i = _i.get<int>();
std::cout << "d_union(42).get<int>() = " << _get_i << std::endl;

// auto _get_auto = _i.get();
// std::cout << "d_union(42).get()" << _get_auto << std::endl;

}

Любые возможные решения будут оценены!

Спасибо

0

Решение

Вы ищете Boost.TypeErasure библиотека. Это позволит вам транслировать любой поток естественным образом. Из учебника:

any<
mpl::vector<
copy_constructible<>,
typeid_<>,
incrementable<>,
ostreamable<>
>
> x(10);
++x;
std::cout << x << std::endl; // prints 11

x здесь может быть любой тип, который удовлетворяет данным понятиям.

Если это не совсем то, что вам нужно, тогда в Boost также есть библиотека различного объединения Variant, которая имеет интерфейс для посетителей.

1

Другие решения

Как правило, когда вы переопределяете глобальные операторы потока для пользовательского типа класса, вы должны реализовать их в терминах вызовов методов-членов и позволить классу решать, как выполнять потоковую передачу, например:

struct d_union {
...
void outputTo(std::ostream &os) const {
if (auto ip = get_pointer<int>())
os << *ip;
else if (auto fp = get_pointer<float>())
os << *fp;
...
}
...
};

std::ostream& operator<<(std::ostream &os, const d_union &u) {
u.outputTo(os);
return os;
}

Это, как говорится, если вы хотите что-то немного больше «авто» когда operator<< вызывается, может быть, вы могли бы попробовать что-то вроде этого (не идеально, но близко к тому, что вы ищете, учитывая d_union не знает, что он держит до времени выполнения, и если вы добавили operator= тогда он может даже динамически менять тип)

typedef void (*pOutputProc)(const d_union&, std::ostream&);

template <typename T>
void outputProc(const d_union &u, std::ostream &os)
{
os << *(u.get_pointer<T>());
}

std::unordered_map<std::type_index, pOutputProc> outputProcs;

template <typename T>
void registerOutputProc()
{
outputProcs[std::type_index(typeid(T))] = &outputProc<T>;
}

void registerOutputProcs()
{
registerOutputProc<int>();
registerOutputProc<float>();
...
}
#pragma startup registerOutputProcs

struct d_union {
...
void outputTo(std::ostream &os) const {
pOutputProc proc = outputProcs[std::type_index(*_type_id)];
if (proc) proc(*this, os);
}
...
};

std::ostream& operator<<(std::ostream &os, const d_union &u) {
u.outputTo(os);
return os;
}

Тогда вам просто нужно будет заселить registerOutputProcs() с различными типами данных, которые вы хотите d_union поддерживать.

0

В общем, это невозможно, поскольку C ++ не является языком с динамической типизацией.

В определенных случаях это будет необходимо для (в вашем случае) operator<<() изучить type_info и делать вещи в зависимости от того, какой тип на самом деле там. Ограничением является то, что необходимо жестко закодировать знание того, какие типы могут храниться в вашем struct — если вы хотите добавить поддержку для разных типов, необходимо будет добавить код и перестроить вашу программу.

auto полагается на то, что компилятор знает тип во время компиляции. type_info получает значения во время выполнения.

0
По вопросам рекламы [email protected]