Ошибка лягушки: неоднозначное преобразование для static_cast - PullRequest
6 голосов
/ 28 марта 2012

У меня есть следующий фрагмент кода:

typedef int AliasB;
typedef unsigned short AliasA;

class Alias
{
public:
    explicit Alias(int someInt) { }

};

// (*) !! below breaks the conversion path via AliasA !!
//typedef Alias AliasA;

class C
{
public:
    C() { }
};

class B
{
public:
    B() { }
    B(const AliasB& value) { }

    operator AliasB() const
    {
        return -1000;
    }

    C combine(const B& someB) 
    {
        return C(); 
    }
};

class A
{
public:
    A() { }

    operator B() const
    {
         return B();
    }

    operator AliasA() const
    {
        return 1001;
        // (*) !! below breaks the conversion path via AliasA !!
        //return AliasA(1000);
    }

    A high() 
    {
        return A(); 
    }
    A low() 
    {
        return A(); 
    }

    C process()
    {
        return (static_cast<B>(low())).combine(static_cast<B>(high()));

        // (**) !! the below compiles fine !! 
        //B theB = low();
        //return theB.combine(high());
    }
};

inline int someFunc(unsigned int someParam, const B& bParam)
{
    return 1;
}

inline A createSomeA()
{
    return A();
}

int main ()
{
    A someA;
    unsigned int counter = 200;
    someFunc(counter, someA);
    //someFunc(counter, static_cast<B>(createSomeA()));
    someA.process();
    return 0;
}

Clang сообщает о следующей ошибке:

clang_static_test.cpp:66:17: error: ambiguous conversion for static_cast from 'A' to 'B'
        return (static_cast<B>(low())).combine(static_cast<B>(high()));
                ^~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
      ^
clang_static_test.cpp:25:5: note: candidate constructor
    B(const AliasB& value) { }
    ^
clang_static_test.cpp:66:48: error: ambiguous conversion for static_cast from 'A' to 'B'
        return (static_cast<B>(low())).combine(static_cast<B>(high()));
                                               ^~~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
      ^
clang_static_test.cpp:25:5: note: candidate constructor
    B(const AliasB& value) { }
    ^
2 errors generated.

Я не могу понять, почему компилятор генерирует ошибку, хотя у меня есть Определен оператор преобразования, и я делаю преобразование в этом конкретном месте явным образом, используя static_cast <>. Код проходит компиляцию с помощью компиляторов GCC 4.5.2 и Visual Studio 2008. Версия Clang - 3.1, созданная мной из репозиториев git Clang и LLVM. пару дней назад.

Итак, Clang сообщает о фактической ошибке? И если да, то почему это ошибка? для меня это не очевидно (я не буду спрашивать, почему другие компиляторы об этом молчат)?

ОБНОВЛЕНИЕ: пример кода теперь представляет собой небольшой скомпилируемый пример (извините, что я не делал этого с первого раза) и повторяющий реальную ситуацию, которая у меня есть. Похоже, что оператор преобразования в AliasA является проблемой, потому что если он удален, то все компилируется нормально. Сейчас неприятно то, что для вышеприведенного фрагмента кода я получаю ошибки также от GCC.

ОБНОВЛЕНИЕ 2 : я добавил код в пример, чтобы лучше отразить мою реальную ситуацию; единственное отличие состоит в том, что для приведенного выше примера я также получаю ошибку от GCC, тогда как для моего реального кода - нет.

Ответы [ 3 ]

3 голосов
/ 11 сентября 2013

Я отправил отчет об ошибке в Clang.Они утверждают, что это не ошибка.Стандарт C ++ не имеет спецификации для этого случая, и поэтому компилятор сообщает о нем как о неоднозначном.См. отчет об ошибке .

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

Что должен делать компилятор, если случай не разрешен явно в стандарте C ++?

  1. Выдать ошибкуmessage
  2. Сделайте логичный выбор по аналогии с другими правилами
  3. Свяжитесь с комитетом по стандартам C ++ и скажите им, чтобы он пересмотрел стандарт.
3 голосов
/ 28 марта 2012

Для static_cast есть два способа конвертировать A в B:

  1. используйте A::operator B и вызовите неявный конструктор копирования B::B(const B& value), чтобы создать новый B

  2. использовать A::operator AliasA, преобразовать результат в AliasB и вызвать B::B(const AliasB& value)

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

    someFunc(counter, static_cast<AliasA>(someA));

Чтобы использовать первый вариант, вы можете опустить приведение, просто написав:

    someFunc(counter, someA);

Ну, я не уверен, хорошо ли настроено последнее поведение, но оно работает по крайней мере с gcc и msvc.

0 голосов
/ 18 июля 2012

Я думаю, что я частично понял, что происходит, но я не думаю, что я понимаю всю ситуацию. Таким образом, пути преобразования, которые видит компилятор, выглядят следующим образом:

              /--------  A  --------\
              |                     |
              |                     |
              B             AliasA(unsigned short)
              |                     |
              |                     |
      copy ctor of B            AliasB(int)
                                    |
                                    |
                           ctor B(const AliasB& value)

Так что это имеет смысл, и компилятор прав, сообщая о неоднозначности (Мне нравятся сообщения об ошибках и предупреждения clan'g). Один из способов заставить его работать - это разорвать путь конвертации через AliasA (см. Комментарии, помеченные (*) в примере кода в вопросе). Это также работает, если я нарушаю оскорбительное выражение и полагаюсь только на неявное преобразование, не пытаясь явно что-то static_cast <> (см. Комментарии, отмеченные (**) в примере кода в вопросе). Но я не совсем понимаю, что происходит за кулисами. Я до сих пор не до конца понимаю, почему он ведет себя по-разному в случае (**) , поскольку пути конвертации кажутся одинаковыми, по крайней мере, для "theB.combine (high ()) " часть.

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