2009-12-22 6 views
6

J'écris une bibliothèque d'interface qui permet l'accès aux variables dans les tables (jusqu'à une profondeur théoriquement infinie) dans un objet de type regula::State. J'accomplis ceci en surchargeant operator[] dans une classe, qui renvoie alors un autre de cette même classe, et appelle operator[] encore comme nécessaire. Par exemple:Pourquoi g ++ dit-il 'aucune correspondance' pour 'opérateur =' alors que c'est clairement le cas, et Visual Studio peut voir qu'il y en a?

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

Ce qui précède est censé placer la valeur 3.14159 dans les variables pi dans le tableau math. Fondamentalement, il le fait en t renvoyer un objet proxy représentant math, qui renvoie un autre objet proxy représentant pi, à laquelle nous sauvegardons réellement la variable. Les internes de ceci ne sont pas vraiment pertinents à la question, mais voici l'en-tête de la fonction.

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

En fait, dans l'exemple ci-dessus, le programme devrait appeler l » operator[]t avec la chaîne "math" et retourner un autre objet, puis appelez operator[] de cet objet avec la chaîne "pi", qui retourne l'objet final, puis assigne la valeur à celui-là en utilisant operator=.

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

Le retour T est juste une copie du value passé.

Maintenant, mon code ne génère AUCUNE erreur dans Visual C++ 2008 et fonctionne parfaitement. Mais lorsque je tente de le compiler sur Linux avec g++, je reçois l'erreur suivante:

../../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&) 

Pour une raison quelconque, g++ semble essayer d'appeler operator= sur operator[], plutôt que sur l'objet retourné comme il est censé être.

Je peux effectivement corriger cette erreur en remplaçant le type de retour sur operator= avec void:

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

Mais ce n'est pas préférable, et d'ailleurs, j'avoir des erreurs similaires dans plusieurs autres endroits avec une operator== De même surchargé:

../../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>())))))’ 

Je ne comprends pas pourquoi cette erreur se produit en g ++, ou pourquoi il ne se produit pas dans Visual C++. Quelqu'un peut-il faire la lumière sur ce sujet ou recommander des solutions?

+4

Code postal réel. Vos échantillons sont cassés. 'regula :: State t [" math "] [" pi "] = 3.14159;' ne peut pas être une instruction C++ valide. La déclaration "fixed" de votre 'operator =' est aussi cassée, car il n'y a plus de 'T' là – AnT

+0

@AndreyT: Je m'excuse, cette ligne a été tronquée alors qu'elle n'aurait pas dû l'être. J'ai corrigé l'échantillon en question. – pdusen

+2

Pouvez-vous résumer à un petit extrait qui démontre l'erreur? – Eclipse

Répondre

6

Section 5.17 de la norme ISO dit

There are several assignment operators, all of which group right-to-left. All require a modifiable lvalue as their left operand, and the type of an assignment expression is that of its left operand. The result of the assignment operation is the value stored in the left operand after the assignment has taken place; the result is an lvalue.

Votre operator= renvoie non seulement le type de mal, mais pas même un lvalue. En supposant que le message d'erreur de GCC n'incluait pas d'autres candidats en plus de operator=(const regula::LObject&), GCC a simplement ignoré complètement votre surcharge. Le operator= il mentionne est la fonction par défaut, générée automatiquement.

À première vue, votre operator[] doit également renvoyer une référence. Comme écrit, aucune expression d'affectation comme votre exemple ne devrait fonctionner du tout.

Donc, vous devriez avoir des fonctions

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

et

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

Eh bien, il est vrai que la façon dont l'opérateur = est déclaré est faux, ce n'est pas nécessairement vrai que l'opérateur [] est déclaré faux. En fait, la spécialisation pour ':: std :: vector ' définit l'opérateur [] pour renvoyer une _Bit_reference (pas une référence réelle). _Bit_reference est à son tour une classe qui définit son propre _Bit_reference & _Bit_reference :: operator = (bool x) '. – Omnifarious

+0

Son opérateur [] est valide; L'opérateur [] n'est pas obligé de renvoyer une lvalue du tout, aussi loin que je m'en souvienne (ne pas le chercher maintenant). Point est, il * l'utilise * comme une lvalue. – Potatoswatter

+0

Eh bien, le résultat de ':: std :: vector :: operator []' est aussi destiné à être utilisé comme une lvalue, et il renvoie un caractère temporaire comme le sien. – Omnifarious