4

Currently I have a member function defined as such:

template<typename T> bool updateParameter(const std::string& name, const T& data);

With an overload for pointers.

template<typename T> bool updateParameter(const std::string& name, T* data);

I would like to be able to use this function as such:

int test = 20;
updateParameter<int>("name", 0);
updateParameter<int>("Referenced parameter", &test);

This way I can have a parameter object that either owns the data that it represents, or points to a user owned member.

Now the problem that I have is with the current setup MSVC implicitly will convert the const 0 of "name" to a pointer, so it ends up calling the overload designed for pointers. I can use the explicit keyword, but then I can't get the implicit conversion from const char[] to std::string for the name parameter. Is there a way of telling the compiler, MSVC and GCC that a certain field should not be implicitly converted, or at least for it to prefer the const T& version over the T* version?

Daniel Moodie
  • 357
  • 1
  • 10

1 Answers1

2

This is a VC++ bug. The first argument's conversion is identical for both overloads (char const[5] => std::string const&).
For the second argument, there are two distinct standard conversion sequences though: For the T const&-overload, the conversion is an identity conversion - §13.3.3.1.4/1:

When a parameter of reference type binds directly (8.5.3) to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type […]

However, converting 0 to a pointer type has Conversion rank. §4.10 goes

A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion.

And §13.3.3.1.1/3 categorizes that accordingly, while also listing our identity conversion and how both relate:

enter image description here


The best workaround is to simply upgrade VC++, as recent versions select the correct overload (e.g. compare with rextester's VC++).
Another option is to take data by reference instead for your second overload. Ambiguities would be prevented by §13.3.3.2/3.2.6. Or simply don't overload updateParameter at all and provide a second function template instead.

Columbo
  • 60,038
  • 8
  • 155
  • 203