ошибка: неоднозначное преобразование типов по умолчанию (c ++) - PullRequest
2 голосов
/ 07 апреля 2011

У меня есть класс, который упаковывает перечисление для легкой печати, сериализации и т. Д.
Я хочу иметь возможность использовать его в операторе switch в качестве традиционного перечисления, поэтому я использовал перегрузчик int () до gcc-4,3.Однако мой код теперь ломается: gcc-4.5.1 .

enum E { consta, constb };
class Wrap {
 private:
  E e;
 public:
  operator E() { return e;}
  operator E() const { return e;}
  operator int() const { return e;} 
  Wrap(E a) : e(a) { }
};

int main() {
  Wrap x(constb);
  x = consta;
  switch (x) { /* Error here */
    case consta: // ..
    case constb: // ..
  }   
  return 0;
} 

Ошибки компилятора:
ошибка: неоднозначное преобразование типов по умолчанию из 'Wrap'
ошибка: кандидатпреобразования включают в себя 'Wrap :: operator E () const' и 'Wrap :: operator int () const'

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

Ответы [ 5 ]

0 голосов
/ 07 апреля 2011

В спецификации указано условие (переключаемое значение):

Условие должно быть целочисленного типа, типа перечисления или типа класса, для которого одна функция преобразования в целое илиТип перечисления существует.

Ваш тип класса имеет 3 функции преобразования в целочисленные или перечислимые типы, поэтому он легко нарушает это ограничение.Это даже не сработает, если вы удалите перегрузку operator int, потому что тогда есть еще 2 функции преобразования.Разрешение перегрузки не происходит.Также нет необходимости в неконстантной operator E перегрузке, если она все равно ничего не пишет

Явное приведение будет безопасной ставкой.Такой же довольно странный способ - использовать op+, но я бы не стал использовать его для ясности

switch (+x) { /* Don't do this in the wild */
  case consta: // ..
  case constb: // ..
}   
0 голосов
/ 07 апреля 2011

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

#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40300
    typedef int E; // workaround
#   define ENUM_TYPE // do not define an enum type as it's not fully supported
#else
#   define ENUM_TYPE E // newer GCC supports enum better
#endif

enum ENUM_TYPE { consta, constb };
#undef ENUM_TYPE

… после этого момента вы можете забыть оОбходной путь, и только один оператор необходим ...

  operator E() const { return e;}
0 голосов
/ 07 апреля 2011

Измените строку на

switch ((E)x) {

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

0 голосов
/ 07 апреля 2011

Разве C ++ не позволяет автоматически преобразовывать перечисление в int, что делает ненужным operator int (например, он будет использовать преобразование E и затем преобразовывать в int)? Я знаю, что вы сказали, что не хотите его удалять, но действительно ли вы подтвердили, что он нарушает совместимость API?

Если это не вариант, вероятно, лучше всего добавить as_int и as_E методы для использования в ситуациях, когда желаемый тип конверсии неоднозначен.

0 голосов
/ 07 апреля 2011

Вы можете устранить неоднозначность, выбрав преобразование самостоятельно с помощью static_cast:

switch(static_cast<E>(x))

Другим вариантом будет сделать один или несколько операторов преобразования explicit - которые разрешатНеоднозначность путем ограничения параметров компилятора.

Однако операторы преобразования explicit доступны только для C ++ 0x, который не поддерживается вашим компилятором.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...