防止模板化成员函数中某些参数的隐式转换

Preventing implicit conversion of some arguments in a templated member function

目前我有一个这样定义的成员函数:

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

指针重载。

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

我希望能够像这样使用此功能:

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

这样我就可以拥有一个参数对象,该对象要么拥有它所代表的数据,要么指向用户拥有的成员。

现在我遇到的问题是当前设置 MSVC 隐式地将 "name" 的 const 0 转换为指针,因此它最终会调用为指针设计的重载。我可以使用 explicit 关键字,但是我无法将名称参数从 const char[] 隐式转换为 std::string。 有没有办法告诉编译器、MSVC 和 GCC 某个字段不应该被隐式转换,或者至少让它更喜欢 const T& 版本而不是 T* 版本?

这是一个 VC++ 错误。两个重载的第一个参数的转换是相同的 (char const[5] => std::string const&).
对于第二个参数,虽然有两个不同的标准转换序列:对于 T const&-重载,转换是身份转换 - §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 […]

但是,将0转换为指针类型具有转换等级。 §4.10 去

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.

§13.3.3.1.1/3 对此进行了相应的分类,同时还列出了我们的身份转换以及两者之间的关系:


最好的解决方法是简单地升级 VC++,因为最新版本 select 是正确的重载(例如与 rextester's VC++ 进行比较)。
另一种选择是通过引用取 data 而不是第二次重载。 §13.3.3.2/3.2.6 可以避免歧义。或者根本不重载 updateParameter 而是提供第二个函数模板。