ambiguose operatoren
-
guten abend
folgendes minimalbeispiel:
template<typename Derived> struct Op { template<typename ScalarType> friend Derived operator* (ScalarType const& Lambda, Derived Rhs) { return Rhs *= Lambda; } }; template<typename T> struct Foo { }; template<typename T> struct Bar : Op<Bar<T> > { template<typename U> Bar operator*= (U) { return *this; } }; template<typename T> void operator* (Foo<T>, Bar<T>) { } int main() { Foo<int>() * Bar<int>(); }gcc 4.8.1 gibt folgendes aus:
prog.cpp: In function ‘int main()’: prog.cpp:33:13: error: ambiguous overload for ‘operator*’ (operand types are ‘Foo<int>’ and ‘Bar<int>’) Foo<int>() * Bar<int>(); ^ prog.cpp:33:13: note: candidates are: prog.cpp:27:6: note: void operator*(Foo<T>, Bar<T>) [with T = int] void operator* (Foo<T>, Bar<T>) ^ prog.cpp:5:17: note: Derived operator*(const ScalarType&, Derived) [with ScalarType = Foo<int>; Derived = Bar<int>] friend Derived operator* (ScalarType const& Lambda, Derived Rhs) ^ich verstehe nicht wie das doppeldeutig sein kann. einer der operatoren nimmt irgendeinen typen an während der andere einen "beschränkteren" typen annimmt. das auflösungssystem in c++ wählt doch immer die am genausten "beschränkte" überladung aus, oder? dann wäre dieser fall hier eindeutig. hat es etwas mit der friend name injection zu tun?
danke im voraus und gruss
ps.: könnt mich gerne aufklären wie man dieses beschränken korrekt bezeichnet. qualifizieren und spezialisieren sind ja beide schon im gebrauch. vll. spezifizieren?
edit: grammatik.
-
Aufklärung:
Du kannst dein Problem auf
template <typename T> struct A {}; template <typename T> struct B {}; struct C {}; template <typename T> void f(A<T>, B<T>) {std::cout<<"a\n";} template <typename T> void f(T, B<C>) {std::cout<<"b\n";} int main() { f(A<C>{}, B<C>{}); }reduzieren, das ist etwas einfacher zu überlegen.
Also schauen wir, ob a (f(A<T>, B<T>)) oder b (f(T, B<C>)) spezialisierter sind:
A<T> ist spezialisierter als T (A<T> ist immer auch ein T' [für T'=A<T>], aber T ist nicht immer ein A<T'> [z.B. T=int])
A<T> ist allgemeiner als B<C> (B<T> ist nicht immer ein B<C> [z.B. T=int], aber B<C> ist immer ein B<T> [für T=C]).a ist spezialisierter als b im ersten Argument, aber b spezialisierter als a im zweiten Argument.
Also ist a spezialisierter als b und b spezialisierter als a => es gibt keine Ordnung zwischen den beiden, beide sind gleich spezialisiert. Damit ist auch die Überladung mehrdeutig.
-
das klingt logisch. ich konnte es im code anpassen. danke für die hilfe.