Неопределенность разрешения перегрузки оператора C ++ - PullRequest
0 голосов
/ 25 апреля 2009

Я пытаюсь переместить античную базу кода C ++ с gcc 3.2 на gcc 4.1, так как столкнулся с несколькими проблемами. Из всех проблем, следующее оставило меня в неведении (я думаю, я провел слишком много времени с Java, или я мог забыть основы C ++ :-P).

У меня есть шаблон класса

template < class T > class XVector < T >
{
   ...
   template < class T > T
   XVector < T >::getIncrement ()
   {
       ...
   }  
   template < class T > int
   XVector < T >::getValue (size_t index, T& value)
   {
      ...
      //The problematic line
      value = (T) (first_value + getIncrement())
                  * (long) (index - first_index);
      ....
   }
}

Этот класс основан на STL std :: vector. У меня есть второй класс TypeValue и его определение, как показано ниже, который может содержать один из int, long и их беззнаковых вариантов, float, double, std :: string. Также перегружает практически все возможные операторы.

class TypeValue
{
    union
    {
        long* _int_value;
        double* _real_value;
        string* _text_value;
    } _value;

    TypeValue();
    explicit TypeValue(long _long);
    explicit TypeValue(int _int);
    explicit TypeValue(unsigned long _ulong);
    ...
    //similarly for all the remaining supported types.
    TypeValue(const TypeValue& ) //Copy constructor

    virtual TypeValue& operator=(const TypeValue &rhs);
    TypeValue& operator+ (TypeValue& )const;
    TypeValue& operator* (TypeValue& )const;
    ...
    //For all the basic operators

    operator long() const;
    operator int() const;
    operator unsigned long() const;
    operator unsigned int() const;
    ...

}

И, наконец, у меня есть другой класс, назовем его build_breaker, который создает объект как XVector < TypeValue > a_variable;. Теперь, когда я компилирую это на gcc 3.2, это компилируется без проблем. Но когда я пытаюсь скомпилировать это на gcc 4.1, я получаю ошибки, говорящие о неоднозначной перегрузке для operator* в классе XVector, а кандидатами являются

operator*(long int, long int) 
operator*(int, long int) 
operator*(long unsigned int, long int) 
operator*(unsigned int, long int) 
operator*(double, long int) 
operator*(float, long int)  

Если бы компилятор сказал, что у него есть проблемы с поиском соответствия для T * long, это имело бы смысл, но почему он пытается типизировать его к нативному типу, а затем выполнить арифметическую операцию? Пожалуйста, помогите мне в этом.

Заранее спасибо.

Ответы [ 3 ]

4 голосов
/ 25 апреля 2009

Второй тип операнда long [int]. Первый - TypeValue, я ожидаю, но нет оператора *, который бы принимал эти два точных типа. Однако для этого оператора существует множество других комбинаций типов, которые компилятор может выбрать, выполнив неявное преобразование первого операнда. Язык позволяет компилятору сделать это, чтобы попытаться найти совпадение.

Но какое из множества преобразований следует выбрать? Компилятор не может выбрать, будет ли int лучше, чем long int. (Вы можете утверждать, что, поскольку второй операнд - long int, это должно быть предпочтительной целью преобразования, но это не так.)

Итак, несколько советов: во-первых, не предоставляйте так много неявных преобразований. Так как класс может содержать только long, double и string, это единственные три преобразования, которые я поставлю. Одно это, вероятно, не решит вашу проблему, но может уменьшить размер вывода ошибок и сделать другие вещи более управляемыми.

Вместо преобразования (index - first_index) в тип long рассмотрите возможность преобразования его в тип T (т. Е. TypeValue) вместо этого, поскольку это, по-видимому, операция, которую вы действительно хотели выполнить в первую очередь.

2 голосов
/ 25 апреля 2009

Я бы изменил все операторы преобразования на именованные функции так, чтобы:

operator long() const;

становится

long ToLong() const;

Неявные разговоры через операторы приведения вызывают всевозможные проблемы, и мои собственные стандарты программирования запрещают их использование.

0 голосов
/ 25 апреля 2009

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

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