Почему g ++ говорит «нет совпадения для« operator = », когда оно явно есть, и Visual Studio может видеть, что оно есть? - PullRequest
6 голосов
/ 22 декабря 2009

Я пишу интерфейсную библиотеку, которая обеспечивает доступ к переменным в таблицах (до теоретически бесконечной глубины) в объекте типа regula::State. Я выполняю это путем перегрузки operator[] внутри класса, который затем возвращает другого из того же класса и снова вызывает operator[] по мере необходимости. Например:

regula::State t;
t["math"]["pi"] = 3.14159;

Вышеуказанное должно поместить значение 3.14159 в переменную pi в таблицу math. По сути, он делает это с помощью t, возвращающего прокси-объект, представляющий math, который возвращает другой прокси-объект, представляющий pi, в который мы фактически сохраняем переменную. Внутренние элементы этого не очень важны для вопроса, но вот заголовок функции.

LObject LObject::operator[] (const std::string name);

По сути, в приведенном выше примере программа должна вызвать t 'operator[] со строкой "math" и вернуть другой объект, а затем вызвать operator[] этого объекта со строкой "pi", которая возвращает последний объект, а затем присваивает значение этому, используя operator=.

template <typename T>
T LObject::operator= (const T& value);

Возвращенное T является просто копией переданного value.

Теперь мой код НЕТ ошибок в Visual C ++ 2008 и работает отлично. Но когда я пытаюсь скомпилировать его в Linux с g++, я получаю следующую ошибку:

../../test/regula-test.cpp:100: error: no match for ‘operator=’ in 
‘L.regula::State::operator[](std::basic_string<char, std::char_traits<char>, 
std::allocator<char> >(((const char*)"Numbers"), ((const std::allocator<char>&)((const 
std::allocator<char>*)(& std::allocator<char>()))))) = Numbers’
../../include/regula.hpp:855: note: candidates are: regula::LObject&
 regula::LObject::operator=(const regula::LObject&)

По какой-то причине g++, кажется, пытается вызвать operator= на operator[], а не на возвращенном объекте, как это должно быть.

Я действительно могу исправить эту ошибку, заменив тип возвращаемого значения на operator= на void:

template <typename T>
/*T*/ void LObject::operator= (const T& value);

Но это не является предпочтительным, и, кроме того, у меня есть подобные ошибки в нескольких других местах с аналогично перегруженным operator==:

../../test/regula-test.cpp:153: error: no match for ‘operator==’ in ‘pi == 
L.regula::State::operator[](std::basic_string<char, std::char_traits<char>, 
std::allocator<char> >(((const char*)"pi"), ((const std::allocator<char>&)((const 
std::allocator<char>*)(& std::allocator<char>())))))’

Я не понимаю, почему эта ошибка возникает в g ​​++ или почему она не возникает в Visual C ++. Кто-нибудь может пролить свет на это или порекомендовать какие-либо решения?

1 Ответ

6 голосов
/ 23 декабря 2009

Раздел 5.17 стандарта ISO гласит

Существует несколько операторов присваивания, каждый из которых группируется справа налево. Все они требуют изменяемого lvalue в качестве своего левого операнда , а тип выражения присваивания соответствует типу его левого операнда . Результатом операции присваивания является значение, сохраненное в левом операнде после присвоения; результат lvalue .

Ваш operator= возвращает не только неправильный тип, но даже не lvalue. Предполагая, что в сообщении об ошибке GCC не было никаких других кандидатов, кроме operator=(const regula::LObject&), GCC просто полностью проигнорировал вашу перегрузку. operator=, которую он упоминает, является автоматически генерируемой функцией по умолчанию.

На второй взгляд, ваш operator[] также должен возвращать ссылку. Как написано, никакие выражения присваивания, подобные вашему примеру, не должны работать вообще.

Итак, у вас должны быть функции

LObject &LObject::operator[] (const std::string name);

и

template <typename T>
LObject &LObject::operator= (const T& value);
...