I believe the problem is that false (and bool()) have value 0, which is also a pointer value in C (and in C++). C++ is attempting to do the least surprising conversion, and in this case getting that 'wrong'. That is why test1 works and test2 does not. I haven't bothered to check with the standard but I am fairly certain what you are seeing is the expected type conversion for this case.
You can design around this by moving the special-case handling of strings in Config::read into special-case handling in Variant::operator<<; that also prevents the current situation where config.read("a", std::string("a")); config.read("b", Variant(std::string("b"))); result in different outputs, something which seems very counterintuitive to me. I've attached some code I threw together to test some of these ideas, which may be worth taking a glance at. BTW, questions of this nature should probably be directed to the gcc-help list rather than the main development mailing list. -Jack On Mon, Dec 26, 2005 at 02:04:52PM -0600, Thomas Braxton wrote: > I have this test code that I think g++ is selecting the wrong function when > the second argument is a zero. If compiled with HAVE_ASCII_DEFAULT 1 it > selects read(const char*, const char*) instead of read(const char*, const > Variant&), for test2a/test3a. If compiled with HAVE_ASCII_DEFAULT 0 > compilation fails because test2a/test3a are ambiguous. Shouldn't all of the > tests select the Variant function, or am I missing something? Why do I have > to explicitly create a Variant when the argument is zero? > > Tested w/ g++ 3.4.3 (Mandrakelinux 10.2 3.4.3-7mdk) and 4.0.1 (self compiled) > > TIA, > Thomas > > PS please CC as I'm not subscribed [attached code snipped]
#include <string> #include <iostream> #include <sstream> #include <map> class type { public: enum type_code { Bool, Int, String, Pointer, None }; std::string as_string() const; type(bool b2) : we_are(Bool), b(b2), i(), s(), p(0) {} type(int i2) : we_are(Int), b(), i(i2), s(), p(0) {} type(std::string s2) : we_are(String), b(b), i(), s(s2), p(0) {} type(char* s2) : we_are(String), b(b), i(), s(s2), p(0) {} type(void* p2) : we_are(Pointer), b(b), i(), s(), p(p2) {} type() : we_are(None), b(), i(), s(), p(0) {} private: type_code we_are; bool b; int i; std::string s; const void* p; }; std::string type::as_string() const { std::stringstream buf; switch(we_are) { case None: buf << "nil"; break; case Int: buf << "int(" << i << ")"; break; case String: buf << "string(\"" << s << "\")"; break; case Pointer: buf << "pointer(" << p << ")"; break; case Bool: buf << "bool(" << (b ? "true" : "false") << ")"; break; default: buf << "<error>"; } return buf.str(); } std::ostream& operator<<(std::ostream& out, const type& t) { out << t.as_string(); return out; } int main() { std::map<std::string, type> types; types["type(nil)"] = type(); types["type(true)"] = type(true); types["type(false)"] = type(false); types["type(bool())"] = type(bool()); types["type(int())"] = type(int()); types["type(0)"] = type(0); types["type((void*)0)"] = type((void*)0); types["type((int*)0)"] = type((int*)0); types["type(1001)"] = type(1001); types["type(\"foo\")"] = type("foo"); types["type(std::string(\"bar\"))"] = type(std::string("bar")); types["type(&types)"] = type(&types); std::map<std::string, type>::const_iterator j; for(j = types.begin(); j != types.end(); j++) std::cout << j->first << " is " << j->second << std::endl; }