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;
   }

Reply via email to