简体   繁体   English

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

[英]add constructor to templated class

I have a templated class holding a value. 我有一个模板化的类持有一个值。 Is it possible to add a constructor to the class to allow implicit conversion like in the example below? 是否可以在类中添加构造函数以允许隐式转换,如下例所示?

Or is there a better way to do this? 或者有更好的方法吗?

#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");
}

Calling f(const Value<std::string>&) with a string literal would require two user-defined conversions ( const char[] ==> std::string ==> Value<std::string> ) in order to match the function parameters, while the standard only allows one. 使用字符串文字调用f(const Value<std::string>&)将需要两个用户定义的转换( const char[] ==> std::string ==> Value<std::string> )以便匹配函数参数,而标准只允许一个。
I see two possibilities to solve that: either overload the constructor or overload f() . 我看到两种可能性来解决这个问题:重载构造函数或重载f()

Assuming you're asking about the former because the latter isn't possible, there are several ways to overload the constructor. 假设您询问前者,因为后者是不可能的,有几种方法可以重载构造函数。

You could exploit the fact that member functions of a class template are only compiled if they are invoked, and add a constructor that only compiles when T is of a certain type. 您可以利用这样一个事实,即只有在调用类模板的成员函数时才会编译它们,并添加一个仅在T属于某种类型时才编译的构造函数。 Of course, if users of your template invoke it for other types, this will result in an error. 当然,如果模板的用户为其他类型调用它,则会导致错误。 However, instead of seeing a problem in this you could embrace it by making the constructor a member template: 但是,您可以通过使构造函数成为成员模板来接受它,而不是在此处看到问题:

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

That way, whatever can be converted into T (as well as T itself, of course) is allowed for U . 这样, U可以转换为T (当然也可以是T本身)。

Or you could specialize the class for std::string . 或者你可以为std::string专门化这个类。 Unfortunately, you would then have to specialize the whole class as there is no selective specialization of individual members. 不幸的是,你必须专注于整个班级,因为没有个别成员的选择性专业化。 So in this case you might want to move all the code into a common (possibly private base class of Value , with the Value base template just defining constructors that forward to the base class' constructors, and a specialization Value<std::string> which adds another constructor taking const char* . 因此,在这种情况下,您可能希望将所有代码移动到一个公共(可能是privateValue基类,其中Value base模板只定义转发到基类的构造函数的构造函数,以及一个特化Value<std::string>它添加了另一个采用const char*构造const char*

You can't. 你不能。 This is an explicit decision by the C++ designers. 这是C ++设计者的明确决定。 The reason is that the compiler would need to go hunting for possible conversions, and in general this would be an infinite hunt. 原因是编译器需要寻找可能的转换,并且通常这将是无限的搜索。

Sure, you think that const char[] ==> std::string ==> Value<std::string> is logical. 当然,您认为const char[] ==> std::string ==> Value<std::string>是合乎逻辑的。 But the compiler doesn't have std::string . 但是编译器没有std::string It just has const char[] ==> ??? 它只有const char[] ==> ??? ==> Value<std::string> , and it would need to find a type in the middle. ==> Value<std::string> ,它需要在中间找到一个类型。 For instance, there might be a class Foo somewhere that has a Foo::Foo(const char*) constructor, and an Foo::operator Value<std::string>() const . 例如,某个class Foo可能有一个Foo::Foo(const char*)构造函数,以及一个Foo::operator Value<std::string>() const That would work, too. 那也行。

As you can see, there's nothing in either const char[] or Value<std::string> that points to Foo. 如您所见, const char[]Value<std::string>没有指向Foo的内容。 Hence, the compiler would have to go on a blind hunt. 因此,编译器必须进行盲目搜索。

As the writer of Value , you do have a choice, though. 作为Value ,你确实有一个选择。 You can inform the compiler that a Value<std::string> can be constructed from any type that std::string::string will accept: 您可以通知编译器可以从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;
};

Now, if you call void f(const Value<std::string> &s) as f("hello") , there's a single implicit conversion Value<std::string>::Value<const char*>(const char* const&) 现在,如果将void f(const Value<std::string> &s)称为f("hello") ,则会有一个隐式转换Value<std::string>::Value<const char*>(const char* const&)

您无法像这样添加到类中,但您可以专门化整个类。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM