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

目前我有一个成员函数定义如下:

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关键字,但是我无法从name char []到std :: string的name参数进行隐式转换.
有没有办法告诉编译器,MSVC和GCC某个字段不应该被隐式转换,或者至少是因为它更喜欢const T&版本超过T *版本?

最佳答案 这是一个VC bug.第一个参数的转换对于两个重载都是相同的(char const [5] => std :: string const&).

对于第二个参数,有两个不同的标准转换序列:对于T const& -overload,转换是一个标识转换 – §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对此进行了分类,同时也列出了我们的身份转换以及两者如何相关:

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

最好的解决方法是简单地升级VC,因为最新版本选择了正确的重载(例如与rextester’s VC++比较).
另一种选择是通过引用获取数据而不是第二次重载. §13.3.3.2/ 3.2.6将阻止歧义.或者根本不要重载updateParameter,而是提供第二个函数模板.

点赞