Overloads resolution crazyness ?
-
Hello, a question around the error C2666, under vc80 (RTM-8.0.50727.4200) Is it compliant to the C++ standard ?
class CondParams { ... static bool getVariableState( const string& s, int& idx, string::size_type* p = NULL; // A static bool getVariableState( string& rs, int& idxVar, const bool& trim ); // B ); bool CondParams::getVariableState( string& rs, int& idx, const bool& trim ) { ... VCF::String::size_type p = 0; bool ok = getVariableState( rs, idx, &p ); if ( ok ) rs = rs.substr( p ); ... }
I get the error message: 1>d:\projs\condparams.cpp(66) : error C2666: 'vcfex::CondParams::getVariableState' : 2 overloads have similar conversions 1> d:\projs\code\condparams.h(130): could be 'bool vcfex::CondParams::getVariableState(string &,int &,const bool &)' 1> d:\projs\code\condparams.h(129): or 'bool vcfex::CondParams::getVariableState(const string &,int &,string::size_type *)' 1> while trying to match the argument list '(string, int, size_type *)' 1> note: qualification adjustment (const/volatile) may be causing the ambiguity I could fix the problem by doing: 1) static bool getVariableState( string& s, int& idx, string::size_type* p = NULL; // A or by doing: 2) bool ok = getVariableState( const_cast(rs), idx, &p ); so I guess that the compiler is confused because it doesn't find any perfect match. The solution 1 is usually not acceptable. So I have to apply 2). But this situation is *very* common: why should I need to specify that a variable is constant each time I am using it as argument for a function that declared that is not going to modify it ? Also it doesn't logically seem necessary. It is like the Standard C++ ( or Microsoft? ) is forcing me to put a const_cast everywhere. This was not a problem with vc70. Similar issue, but not identical, with an example given in vc80 RTM help about the C2666 error.enum E { E_A, E_B }; class A { int h(const E e) const {return 0; } int h(const int i) { return 1; } // Uncomment the following line to resolve. // int h(const E e) { return 0; } void Test() { h(E_A); // C2666 h((const int) E_A); h((int) E_A); } };
Why the compiler shouldn't be smart enough to understand that int h(const E e) is a better match than int h(const int i) ? Why in earth int h(const E e) solves the problem, while int h(const E e) co -
Hello, a question around the error C2666, under vc80 (RTM-8.0.50727.4200) Is it compliant to the C++ standard ?
class CondParams { ... static bool getVariableState( const string& s, int& idx, string::size_type* p = NULL; // A static bool getVariableState( string& rs, int& idxVar, const bool& trim ); // B ); bool CondParams::getVariableState( string& rs, int& idx, const bool& trim ) { ... VCF::String::size_type p = 0; bool ok = getVariableState( rs, idx, &p ); if ( ok ) rs = rs.substr( p ); ... }
I get the error message: 1>d:\projs\condparams.cpp(66) : error C2666: 'vcfex::CondParams::getVariableState' : 2 overloads have similar conversions 1> d:\projs\code\condparams.h(130): could be 'bool vcfex::CondParams::getVariableState(string &,int &,const bool &)' 1> d:\projs\code\condparams.h(129): or 'bool vcfex::CondParams::getVariableState(const string &,int &,string::size_type *)' 1> while trying to match the argument list '(string, int, size_type *)' 1> note: qualification adjustment (const/volatile) may be causing the ambiguity I could fix the problem by doing: 1) static bool getVariableState( string& s, int& idx, string::size_type* p = NULL; // A or by doing: 2) bool ok = getVariableState( const_cast(rs), idx, &p ); so I guess that the compiler is confused because it doesn't find any perfect match. The solution 1 is usually not acceptable. So I have to apply 2). But this situation is *very* common: why should I need to specify that a variable is constant each time I am using it as argument for a function that declared that is not going to modify it ? Also it doesn't logically seem necessary. It is like the Standard C++ ( or Microsoft? ) is forcing me to put a const_cast everywhere. This was not a problem with vc70. Similar issue, but not identical, with an example given in vc80 RTM help about the C2666 error.enum E { E_A, E_B }; class A { int h(const E e) const {return 0; } int h(const int i) { return 1; } // Uncomment the following line to resolve. // int h(const E e) { return 0; } void Test() { h(E_A); // C2666 h((const int) E_A); h((int) E_A); } };
Why the compiler shouldn't be smart enough to understand that int h(const E e) is a better match than int h(const int i) ? Why in earth int h(const E e) solves the problem, while int h(const E e) coFor the first situation...
VCF::String::size_type
andstring::size_type
are not the same type, so neither of the function calls match perfectly. However, both could match using implicit casting rules, hence the ambiguity. If you intend to call the first one, make sure the parameter isstring::size_type
rather thanVCF::String::size_type
For the second situation... Again, neither overload matches perfectly. You're calling a function calledh
from a non-constthis
pointer. The compiler can either implicitly convertthis
to a const pointer and call the first one, or it can implicitly convertE
to anint
and call the second one. Neither conversion has preference over the other, so there is an ambiguity. The reason uncommenting the other definition ofh
works is because it is a perfect match to the function call - there is no conversion required.Ryan
"Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
-
For the first situation...
VCF::String::size_type
andstring::size_type
are not the same type, so neither of the function calls match perfectly. However, both could match using implicit casting rules, hence the ambiguity. If you intend to call the first one, make sure the parameter isstring::size_type
rather thanVCF::String::size_type
For the second situation... Again, neither overload matches perfectly. You're calling a function calledh
from a non-constthis
pointer. The compiler can either implicitly convertthis
to a const pointer and call the first one, or it can implicitly convertE
to anint
and call the second one. Neither conversion has preference over the other, so there is an ambiguity. The reason uncommenting the other definition ofh
works is because it is a perfect match to the function call - there is no conversion required.Ryan
"Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
Thank you very much for the reply. Please forget about the VCF::String thing. It was a typo on my side. Here is a code I made for this question ( it compiles
class Cond { public: typedef std::basic_string MyString; Cond() { }; virtual ~Cond(void) { }; Cond( const Cond& other ) { /* simple implementation just for this example */ *this = other; }; Cond& operator= ( const Cond& other ) { return *this; }; // implementation bool split( const MyString& s, MyString::size_type* p = NULL ); bool split( MyString& s, const bool& trim ); }; inline bool Cond::split( const MyString& s, MyString::size_type* p ) { /* simple implementation just for this example */ return true; } inline bool Cond::split( MyString& s, const bool& trim ) { MyString::size_type p; //if ( split( const_cast(s), &p ) ) // this compiles fine if ( split( s, &p ) ) // C2666 { s = s.substr( p + 1 ); return true; } return false; }
I get the error message: 1>d:\projs\libraries\vcfex\src\conditions\test.h(51) : error C2666: 'vcfex::Cond::split' : 2 overloads have similar conversions 1> d:\projs\libraries\vcfex\src\conditions\test.h(37): could be 'bool vcfex::Cond::split(vcfex::Cond::MyString &,const bool &)' 1> d:\projs\libraries\vcfex\src\conditions\test.h(36): or 'bool vcfex::Cond::split(const vcfex::Cond::MyString &,stlp_std::basic_string<_CharT,_Traits,_Alloc>::size_type *)' 1> with 1> [ 1> _CharT=wchar_t, 1> _Traits=stlp_std::char_traits, 1> _Alloc=stlp_std::allocator 1> ] 1> while trying to match the argument list '(vcfex::Cond::MyString, stlp_std::basic_string<_CharT,_Traits,_Alloc>::size_type *)' 1> with 1> [ 1> _CharT=wchar_t, 1> _Traits=stlp_std::char_traits, 1> _Alloc=stlp_std::allocator 1> ] 1> note: qualification adjustment (const/volatile) may be causing the ambiguity It puzzles me that the C++ standard ( or is just vc80 ? ) is asking me to specify const_cast when intuitively the compiler should resolve the two overloads 'without effort'. A comment on this after the next point. I understand what you say at the second point. I agree but I am really surprised at the same time. I always considered a const function just as a way to tell the compler that that function is not going to change the 'this' pointer. So I ca -
Thank you very much for the reply. Please forget about the VCF::String thing. It was a typo on my side. Here is a code I made for this question ( it compiles
class Cond { public: typedef std::basic_string MyString; Cond() { }; virtual ~Cond(void) { }; Cond( const Cond& other ) { /* simple implementation just for this example */ *this = other; }; Cond& operator= ( const Cond& other ) { return *this; }; // implementation bool split( const MyString& s, MyString::size_type* p = NULL ); bool split( MyString& s, const bool& trim ); }; inline bool Cond::split( const MyString& s, MyString::size_type* p ) { /* simple implementation just for this example */ return true; } inline bool Cond::split( MyString& s, const bool& trim ) { MyString::size_type p; //if ( split( const_cast(s), &p ) ) // this compiles fine if ( split( s, &p ) ) // C2666 { s = s.substr( p + 1 ); return true; } return false; }
I get the error message: 1>d:\projs\libraries\vcfex\src\conditions\test.h(51) : error C2666: 'vcfex::Cond::split' : 2 overloads have similar conversions 1> d:\projs\libraries\vcfex\src\conditions\test.h(37): could be 'bool vcfex::Cond::split(vcfex::Cond::MyString &,const bool &)' 1> d:\projs\libraries\vcfex\src\conditions\test.h(36): or 'bool vcfex::Cond::split(const vcfex::Cond::MyString &,stlp_std::basic_string<_CharT,_Traits,_Alloc>::size_type *)' 1> with 1> [ 1> _CharT=wchar_t, 1> _Traits=stlp_std::char_traits, 1> _Alloc=stlp_std::allocator 1> ] 1> while trying to match the argument list '(vcfex::Cond::MyString, stlp_std::basic_string<_CharT,_Traits,_Alloc>::size_type *)' 1> with 1> [ 1> _CharT=wchar_t, 1> _Traits=stlp_std::char_traits, 1> _Alloc=stlp_std::allocator 1> ] 1> note: qualification adjustment (const/volatile) may be causing the ambiguity It puzzles me that the C++ standard ( or is just vc80 ? ) is asking me to specify const_cast when intuitively the compiler should resolve the two overloads 'without effort'. A comment on this after the next point. I understand what you say at the second point. I agree but I am really surprised at the same time. I always considered a const function just as a way to tell the compler that that function is not going to change the 'this' pointer. So I caMarcello wrote:
So at the end it seems that the standard C++ is treating a difference betweenconst and non-const at the same level as a difference between types completelyunrelated. This, even when the the const specifier is just there to tell thatwhat is specified as const will not be changed by the function using that instance
const
isn't just there to portray information to the compiler, it actually changes the type. Sochar*
andconst char*
are as different (to the compiler) aschar*
andfloat
. The difference between the two examples is that the compiler has rules for implicity converting between the first pair, but not the second. Soconst
on a function definition doesn't just tell the compiler that the function doesn't modify any of the class members, it also changes the way the compiler handles ambiguity resolution, as you've found out - because the type of the function is different. Incidentally, this is also why you can have two identical function signatures that differ only in their "constness" - they are different types. As for your first point, neither of the functions is an exact match, but both of them can be satisfied by implicit conversion rules, so the call is ambiguous. In this case, the first parameter is aMyString&
, which matches the second function but not the first, and the second parameter is aMyString::size_type*
which matches the first function, but not the second. However,MyString&
can be implicitly converted toconst MyString&
, and alsoMyString::size_type*
can be implicitly converted toconst bool&
, and the compiler really has no way of knowing which you intended. It has no choice but to flag the ambiguity. Casting either parameter explicitly should remove the ambiguity. As you have hinted, the VS2005 compiler is much more strict than previous compilers, but it is behaving according to the standard.Ryan
"Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"