【问题标题】:Template class constructor overload resolution模板类构造函数重载解析
【发布时间】:2013-11-05 18:45:08
【问题描述】:

我有一个关于类模板的 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 * 匹配?这种情况可以通过将 ctor 2 中的 const char * 更改为 const string &amp; 来解决。但是这样做,boolType b("test", "true") 现在会匹配到 ctor 1 而不是 ctor 2。

我的要求是:

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

限制是:

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

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

【问题讨论】:

  • 只保留模板构造函数,将其特化为 T=char const*
  • typedef TemplateClassTest&lt;int&gt; u32Type; 将解决问题,因为 ctor 1 成为精确匹配。我不确定这是否会破坏一些不同的东西,因为 int 不需要正好有 32 位。
  • 这是为什么 C++11 添加了 nullptr 关键字的完美示例。
  • @DyP:假设我已经有另一个 typedef TemplateClassTest intType;
  • @CodeWarrior 1) ctor 是私有的。 2) 显式特化类模板的成员函数的外联定义不包含显式特化类模板的template&lt;&gt;。只需使用TemplateClassTest&lt;bool&gt;::TemplateClassTest(const string&amp;, const char*) { /*..*/ }

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


【解决方案1】:

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

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

这两种转换,空指针转换积分转换,具有相同的等级(Conversion),因此有歧义。


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

【讨论】:

  • 感谢您的回复..为什么它不匹配 ctor 1,因为它应该有更好的排名..因为在这种情况下 0 也是类型 T...我应该如何制作 u32Type v( "test", 0) 和 boolType b("test", "true") 来匹配单独的 ctor's?
  • @CodeWarrior 0 作为整数文字是 int 类型,而不是 unsigned long long int 类型。
猜你喜欢
  • 1970-01-01
  • 2019-10-24
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
  • 1970-01-01
相关资源
最近更新 更多