模板类构造函数重载决策

时间:2013-11-05 18:45:08

标签: c++ templates constructor overload-resolution constructor-overloading

我有一个关于类模板的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)是不明确的。

为什么intconst char *匹配?这种情况可以通过将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()中的用户代码调用。

非常感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

这是不明确的,因为0是一个空指针常量。空指针常量可以隐式转换为任何指针类型 - &gt; 空指针转换。因此,ctor 2是可行的:TemplateClassTest(const string&, const char*)

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

这两个转换,空指针转换积分转换,具有相同的等级(转换),因此含糊不清。


[conv.ptr] / 1

  

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


与您的约束相匹配的可能但难看的修复方法是将第二个构造函数更改为:

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;
}