2014-12-30 5 views
1

ОК, стандарт по-прежнему говорит о том, что инициализация объединения в виде скобок инициализирует только первый элемент. Полагаю, это ставит этот вопрос больше в «Не было бы хорошо, если бы ...?» категория.Сделать инициализатор C++ автоматически определять член профсоюза?

Должно быть, это так? В конце концов, теперь у нас есть автоматическое определение типа для других типов.

auto x = 3; // int 
auto s = "foo"; // char * 
auto w = L"Foo"; // wchar_t * 

Так почему бы и нет с профсоюзом? Дано:

struct init 
{ 
int t; 
union { 
    long long x; 
    char *s; 
    wchar_t *w; 
}; 
}; 

В настоящее время вы можете только скобки инициализации init::xint), не s или w.

Автоматическое определение типа может быть расширен таким образом, чтобы член профсоюза инициализируется выбирается на основе типа инициализатора: (. Конечно, это не должно составить в текущем стандарте)

auto init initial_data [] = { 
{ 0, 3 },  // initializes x, brace elision 
{ 1, "foo" }, // initializes s 
{ 2, L"Foo" } // initializes w 
}; 

Это позволит разместить все initial_data в одном списке инициализаторов. (Я подозреваю, что ключевое слово auto должно было бы отправиться куда-то еще).

Есть ли что-то, что делает это плохой идеей (за исключением «никто не думает об этом еще» или «это слишком сложно реализовать»)? В настоящее время вы должны сделать что-то чудовищное, как:

#define RI(X) reinterpret_cast<long long>(X) 
const init initial_data[] = { 
{ 0, 3 },  // initializes x, brace elision 
{ 1, RI("foo") }, // initializes s 
{ 2, RI(L"Foo") } // initializes w 
}; 

Я не хотел бы пройти через эти искривления, за исключением того, что std::exception должен быть инициализирован с std::string (т.е. на основе char), так что я не могу просто имеют список инициализаций со всеми wchar_t*. И мне бы очень хотелось, чтобы все эти инициализаторы находились там же.

+0

'повышение :: variant' имеет такое поведение (по большому счету, остерегайтесь неоднозначных конструктора перегрузок между типами элементов варианта) – sehe

ответ

3

Update

В моем введении я говорил:

(хотя Объединение может иметь функции-члены (в том числе конструкторов и деструкторов)

Я просто понял, что это позволяет вы сами сами создаете необходимые конструкторы!

struct init { 
    init(long long v) : t(type::longlong), x(v) {} 
    init(char const* v) : t(type::pcsz),  s(v) {} 
    init(wchar_t const* v) : t(type::pwcsz), w(v) {} 

    enum class type { longlong, pcsz, pwcsz } t; 
    union { long long x; char const* s; wchar_t const* w; }; 
}; 

Теперь это составляет:

init initial_data [] = { 
    3 ,  // initializes x, brace elision 
    "foo" , // initializes s 
    L"Foo" // initializes w 
}; 

Посмотри Live On Coliru


Q. Есть ли что-то делает это плохая идея (за "ничей мысли об этом еще" или «это слишком сложно реализовать»)

Вообще union очень часто плохая идея. Трудно их безопасно использовать.В этом отношении они являются гражданами второго класса в C++ (хотя в наши дни объединение может иметь функции-члены (включая конструкторы и деструкторы), но не виртуальные функции).

Позволяет компилятору выбрать «слот» для получения инициализатора, скорее всего, столкнется с неопределенностями очень скоро.

С инициализацией скобок они могут добавить некоторые ограничения (без сужения/расширения конверсий), как есть, с списками инициализаторов в C++ 11.

Но это все фантазия. Короче говоря: это не функция языка.


boost::variant имеет такое поведение.

Примечание

  • which() член в основном ваш типа дискриминатор (t)
  • вы можете оптимизировать размер: BOOST_VARIANT_MINIMIZE_SIZE
  • вы должны сделать полукокс/wchar_t указатели const*, если вы хотите назначить из буквально!

Live On Coliru

#define BOOST_VARIANT_MINIMIZE_SIZE 
#include <boost/variant.hpp> 

using init = boost::variant<long long, char const*, wchar_t const*>; 

#include <iostream> 

int main() { 
    init initial_data [] = { 
     3 ,  // initializes x, brace elision 
     "foo" , // initializes s 
     L"Foo" // initializes w 
    }; 

    for(auto& v : initial_data) 
     std::cout << v.which() << "\t" << v << "\n"; 
} 

Выход:

0 3 
1 foo 
2 0x401f14 
+0

'boost :: variant' имеет нетривиальные конструкторы копирования и операторы присваивания, поэтому он не является совокупностью, и, следовательно, не должны быть готовы к инициализации? – Spencer

+0

@SpencerSimpson действительно, это не совокупность. Это скобка, инициализируемая в _uniform intialization_, которая была введена в C++ 11 (хотя я не удалял фигурные скобки в редакторе. Теперь это просто использование универсального конструктора преобразования) – sehe

+0

Во всяком случае, кажется, что много кода просто для хранения некоторых данных это просто будет скопировано где-то в другом месте, и вопрос в том, должен ли сам язык делать это. – Spencer

Смежные вопросы