1

I have a delima. I'm using wrapper classes for native types, however, when using the wrapper types as function arguments, the implicit conversion for char pointer to bool keeps causing the compiler to issue an ambiguous function call error:

class VBool
{
   public:
      VBool(bool b):value(b){}

      template<class T>
      VBool(T)=delete;

   private:
      bool value;
};

class VString
{
   public:
      VString(const char* str):value(str){}

   private:
      std::string value;
};

void processVType(VBool vb){}
void processVType(VString vs){}

int main()
{
   processVType(""); // rejected as ambiguous by compiler.

   return 0;
}

Now the compiler allows: VBool b = true; And correctly rejects: VBool b = "string";

But how do I get the compiler to correctly identify the intended function version to be called?

Note: I'm using VCC compiler with language standard for C++17 enabled.

SirKM
  • 60
  • 5

1 Answers1

0

Add another function with proper parameter.

inline void processVType(const char* vs) { processVType(VString(vs)); }

Just out of curiosity, why are you trying to implement something like this?

zdenek
  • 21,428
  • 1
  • 12
  • 33
  • Doesn't that defeat the purpose of "delete"-ing the constructor? I'm trying to implement wrapper classes that accept only the intended types as initializers (no implicit conversions). Your suggestion basically requires anyone using the wrappers to, of necessity, create overloaded versions of any functions that use the wrapper classes. – SirKM Apr 26 '18 at 21:21
  • If you don't want to use implicit conversions, then don't use it. Mark all your constructors as `explicit`. The fact is, that all your code depend on implicit conversions. `""` is neither `VString` nor `VBool`. It's `const char*` and pointers in C++ can be implicitly cast to `bool`. Thanks to it you can call `const char *x = nullptr; if (x) { // do something}`. That's the source of the ambiguity. `""` Can be implicitly converted to `VString` and `VBool`. – zdenek Apr 27 '18 at 06:23
  • I guess my real confusion comes from the fact that if I try to initialize a `VBool` instance with a `const char *` the compiler rejects it, correctly so. However, somehow it still sees `VBool` as a valid conversion from `const char *` even though that constructor was `delete`-ed. What is the rationale for it doing that? – SirKM Apr 27 '18 at 23:33
  • If you mark a constructor as deleted it doesn't mean the constructor disappears from a namespace. The deleted constructor is still declared. It only has no implementation and is marked as deleted. The compiler in your case don't know if choose `VBool(const char *) = deleted` and report compile error or if choose `VString(const char *)`. – zdenek Apr 28 '18 at 12:26
  • Thanks for the explanation. In my mind, I just figured if the compiler has to choose between an option that would generate a compile time error and option that is not an error, then it would logically choose the latter. But I guess that is, unfortunately, not specified by the standard. – SirKM Apr 28 '18 at 14:36