c ++ приведение объединения к одному из его типов-членов

Следующее кажется мне совершенно логичным, но неверным C ++. Объединение не может быть неявно приведено к одному из его типов-членов. Кто-нибудь знает вескую причину, почему бы и нет?

union u {
  int i;
  char c;
}
function f(int i) {
}
int main() {
  u v;
  v.i = 6;
  f(v);
}

И может ли кто-нибудь предложить чистую альтернативу (самый чистый, который я могу придумать, это f(v.i);, который, я признаю, очень чистый, но приведенное выше кажется еще более чистым)


person Baruch    schedule 20.02.2011    source источник
comment
Это как ты сказал. Вы называете f (v.i)   -  person CashCow    schedule 21.02.2011
comment
использование объединения вместо его членов означает, что я могу заменить его любым из них, не беспокоясь о том, какой из них он на самом деле использует.   -  person Baruch    schedule 21.02.2011
comment
И тем самым разрушая любую способность компилятора помогать вам с типами. Я вообще не думаю, что это хорошая идея.   -  person Omnifarious    schedule 21.02.2011


Ответы (5)


Соглашаясь с Сумасшедшим Эдди, что мне кажется, что это не так лучше, вы можете получить неявное преобразование, определив его:

union u {
    int i;
    char c;
    operator int () const { return i; }
    operator char () const { return c; }
};
person 6502    schedule 20.02.2011
comment
Я склонен голосовать против, неявные преобразования являются источником больше проблем, чем преимуществ, и в то же время они решают только часть проблемы, поскольку позволяют f(v), если аргумент f является либо int, либо const int&, но не сработает с int&. Кроме того, если функция сохраняет ссылку (случай const int&), которая будет относиться не к v.i, а к временному --will в конце полного выражения, не будет обновляться по мере изменения u.i ... что может привести к неожиданному поведению - person David Rodríguez - dribeas; 21.02.2011
comment
Я согласен, что это плохая идея, и я бы никогда не использовал этот материал, но это то, о чем просил исходный плакат (неявное приведение от объединения к члену), и может быть, что в его / ее варианте использования это имеет смысл . Обратите внимание, что все перечисленные вами проблемы также присутствуют при передаче int функции, ожидающей double или const double&. - person 6502; 21.02.2011
comment
Да, я согласен. Вы решили проблему OP и не заслуживаете голосования против. Однако очень сомнительно, должен ли OP делать это в первую очередь. - person Omnifarious; 21.02.2011
comment
@Omnifarious, то, на мой взгляд, кто-то должен проголосовать против или прокомментировать вопрос, а не правильные ответы - person ToxiCore; 21.11.2016

Как компилятор узнает, какой член использовать? Ему нужно будет отслеживать, какой член был назначен последним, чтобы он знал, во что преобразовать. Это называется помеченным объединением, и хотя язык, безусловно, может указать такую ​​вещь, это не так (это пережиток C).

Но это нормально, потому что у нас есть boost::variant. Он не только безопаснее и гибче, чем профсоюзы, но и более эффективен. Вы можете применить посетителей к варианту, и он вызовет (посетит) указанную функцию с любым активным членом, без дальнейшей работы со стороны пользователя.

person GManNickG    schedule 20.02.2011
comment
Нет, не будет. Совершенно законно назначать одного участника и читать другого. - person Baruch; 21.02.2011
comment
@baruch: Вы совершенно ошиблись. Фактически, самое первое предложение, описывающее объединения, таково: в объединении не более одного из элементов данных может быть активным в любое время, то есть значение не более одного из элементов данных может быть сохранено в объединении в любое время. время. Неопределенное поведение - писать в один элемент, а не читать из другого. - person GManNickG; 21.02.2011
comment
Одним из возможных источников путаницы является то, что C и C ++ отличаются в этом отношении. Чтение члена, отличного от последнего назначенного, поощряется стандартом C. - person Leushenko; 22.09.2015

Причина, по которой это не доступно неявно (по умолчанию), заключается в том, что это может быть неоднозначным. Совершенно законно иметь более одного участника с одним и тем же типом, и не было бы причин отдавать предпочтение одному или другому.

union u
{
    char c;
    TCHAR t;
    wchar_t w;
    int i;
};
void f(TCHAR);

u v;
f(v); // which member should be used?
person Ben Voigt    schedule 20.02.2011
comment
Если существует один или несколько членов одного и того же типа, не имеет значения, какой из них использует компилятор, поскольку все они занимают одно и то же пространство. - person dreamlax; 21.02.2011
comment
@dreamlax: верный аргумент во всех практических реализациях. К сожалению, по стандарту это имеет значение. - person Ben Voigt; 21.02.2011

Я не знаком с другим синтаксисом. Честно говоря, доступ к члену профсоюза напрямую довольно ясен и лаконичен.

Я предполагаю, что причина отсутствия неявного приведения типов заключается в некотором правиле, согласно которому технически «неопределенное поведение» - запись в один член объединения, а затем чтение из другого члена.

Неявно приведенный тип может быть не последним, в который записывается. Хотя это прекрасно компилируемый код и он вероятно будет работать нормально, компилятор, в принципе, не должен автоматически или неявно делать что-то, что противоречит самим правилам, которые он применяет.

person Sion Sheevok    schedule 20.02.2011

Кто-нибудь знает вескую причину, почему нет?

function f(char c) {
    doStuff(c);
}

Лучшая причина, которую я могу придумать.

А может кто-нибудь предложить чистую альтернативу?

Я с Сумасшедшим Эдди на этом; f(v.i) настолько "чист", насколько это возможно, не вызывая ошибок программиста. Два дополнительных символа - приемлемая цена за более надежный код, не так ли?

person Cheezmeister    schedule 20.02.2011