将构造函数添加到模板化类

时间:2010-12-07 09:43:56

标签: c++

我有一个模板化的类持有一个值。是否可以在类中添加构造函数以允许隐式转换,如下例所示?

或者有更好的方法吗?

#include <string>

template<typename T>
class Value
{
  public:
    Value(const T& value) : m_value(value) { };
  private:
    T m_value;
};

// I thought adding something like this would do the trick but it does not work:
/*
template<>
class Value<std::string>
{
  public:
    Value(const char *sz) : m_value(sz) { };
}
*/

void f(const Value<std::string> &s)
{
}

int main()
{
  f(std::string("hello"));

  // I want to have this working:
  f("hello");
}

4 个答案:

答案 0 :(得分:4)

使用字符串文字调用f(const Value<std::string>&)需要两次用户定义的转换(const char[] ==&gt; std::string ==&gt; Value<std::string>)才能匹配功能参数,而标准只允许一个。
我看到有两种可能解决这个问题:重载构造函数或重载f()

假设您询问前者,因为后者是不可能的,有几种方法可以重载构造函数。

您可以利用以下事实:只有在调用类模板的成员函数时才会编译它们,并添加仅在T属于某种类型时才编译的构造函数。当然,如果模板的用户为其他类型调用它,则会导致错误。 但是,您可以通过使构造函数成为成员模板来接受它,而不是在此中看到问题:

template<typename U>
Value(const U& value) : m_value(value) { };

这样,T允许转换为T(当然还有U本身)。

或者你可以专门为std::string上课。不幸的是,你必须专门化整个班级,因为没有个别成员的选择性专业化。因此,在这种情况下,您可能希望将所有代码移动到一个公共(可能private基类Value中,Value基本模板只定义转发到基类的构造函数'构造函数和专门化Value<std::string>,它添加了另一个构造函数const char*

答案 1 :(得分:2)

你做不到。这是C ++设计者的明确决定。原因是编译器需要寻找可能的转换,并且通常这将是无限的搜索。

当然,您认为const char[] ==&gt; std::string ==&gt; Value<std::string>是合乎逻辑的。但是编译器没有std::string。它只有const char[] ==&gt; ??? ==&gt; Value<std::string>,它需要在中间找到一个类型。例如,某处class Foo可能有Foo::Foo(const char*)构造函数和Foo::operator Value<std::string>() const。那也行。

正如您所看到的,const char[]Value<std::string>中没有指向Foo的内容。因此,编译器必须进行盲目搜索。

作为Value的作者,你确实可以做出选择。您可以通知编译器可以从std :: string :: string接受的任何类型构造Value<std::string>

template<typename T>
class Value
{
  public:
    Value(const T& value) : m_value(value) { };
    // Intentionally not "explicit"
    template<typename U> Value(const U& value) : m_value(value) { };
  private:
    T m_value;
};

现在,如果您将void f(const Value<std::string> &s)称为f("hello"),则只有一次隐式转化Value<std::string>::Value<const char*>(const char* const&)

答案 2 :(得分:1)

你不能像这样添加到类中,但是你可以专门化整个类。

答案 3 :(得分:1)

尝试this

template<typename T>
class Value
{
  public:
    Value(const T& value) : m_value(value) { }
    Value(const char* a): m_value(a){} // add this
  private:
    T m_value;
};