1

我对类模板的 ctor 重载解析有一个简单的问题:

#include <iostream>
#include <string>

using namespace std;
enum EnumTypeVal { READ, WRITE };

template <class T>
class TemplateClassTest {
public:
    TemplateClassTest(const string & stringVal, T typeVal, EnumTypeVal e = READ,
                      const string & defaultStringVal = "default");
    TemplateClassTest(const string & stringVal, const char * charVal);
    TemplateClassTest(const string & stringVal, EnumTypeVal e = READ,
                      const string & defaultStringVal = "default");
private:
T type;
};

template <class T>
TemplateClassTest<T>::TemplateClassTest(const string & stringVal, T typeVal,
                                        EnumTypeVal e,
                                        const string & defaultStringVal)
{
    type = typeVal;
    cout << "In TemplateClassTest(const string &, T, EnumTypeVal, "
            "const string &)" << endl;
}

template <class T>
TemplateClassTest<T>::TemplateClassTest(const string & stringVal,
                                        const char * charVal)
{
    cout << "In TemplateClassTest(const string &, const char *)" << endl;
}

template <class T>
TemplateClassTest<T>::TemplateClassTest(const string & stringVal, EnumTypeVal e,
                                        const string & defaultStringVal)
{
    cout << "In TemplateClassTest(const string &, EnumTypeVal, const string &)"
         << endl;
}

typedef TemplateClassTest<long long unsigned int> u32Type;
typedef TemplateClassTest<bool> boolType;

int main()
{
    u32Type l("test", "0"); //matches ctor 2
    u32Type v("test", 0); // ambiguity between ctor 1 and 2
    boolType b("test", "true"); //matches ctor 2
    return 0;
}

第二次调用编译失败,抛出错误:

重载 'TemplateClassTest(const char [5], int) 的调用不明确。

为什么int匹配到const char *?这种情况可以通过将 ctor 2 中的 to 更改来解决const char *const string &但是这样做,boolType b("test", "true")现在匹配到 ctor 1 而不是 ctor 2。

我的要求是:

  • u32Type v("test", 0)应该匹配 ctor 1
  • boolType b("test", "true")应该匹配 ctor 2。

限制是:

  • ctor 1 和 3 签名无法更改
  • main() 中的用户代码调用无法更改。

任何帮助都非常感谢..谢谢!

4

1 回答 1

1

它是模棱两可的,因为它0是一个空指针常量。空指针常量可以隐式转换为任何指针类型 ->空指针转换。因此,ctor 2 是可行的:TemplateClassTest(const string&, const char*).

作为整数文字,0类型为int. 因此,构造函数 1TemplateClassTest(const string&, T, EnumTypeVal = READ, const string & = "default")需要从int到的转换unsigned long long->整数转换

这两个转换,空指针转换整数转换,具有相同的等级(转换),因此存在歧义。


[conv.ptr]/1

空指针常量是整数类型的整数常量表达式纯右值,其计算结果为零或类型的纯右值std::nullptr_t。空指针常量可以转换为指针类型;结果是该类型的空指针值,并且可以与对象指针或函数指针类型的所有其他值区分开来。这种转换称为空指针转换


与您的约束匹配的一个可能但丑陋的修复是将第二个构造函数更改为:

template<class U,
         class V = typename std::enable_if<std::is_same<U, const char*>{}>::type>
TemplateClassTest(const string & stringVal, U charVal);

也就是说,一个贪婪的构造函数模板,被 SFINAE 限制为只接受const char*作为第二个参数。这严重限制了在尝试匹配此 ctor 时应用于第二个参数的隐式转换。

外联定义变为:

template <class T>
template<class U, class V>
TemplateClassTest<T>::TemplateClassTest(const string & stringVal, U charVal)
{
    cout << "In TemplateClassTest(const string &, const char *)" << endl;
}
于 2013-11-05T18:52:39.113 回答