我有一个模板化的类持有一个值。是否可以在类中添加构造函数以允许隐式转换,如下例所示?
或者有更好的方法吗?
#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");
}
答案 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;
};