带模板参数的函数调用

Function call with template parameter

我写了一个简单的class模板:

template <class T>
class my_class
{
public:
    my_class(T value)
        : my_Value(value)
    {
    }
private:
    T my_Value;
};

现在我可以在一个简单的函数签名中使用这个模板,例如:my_function(my_class<std::string> my_string)

当我想调用函数时,我可以很容易地使用它:

auto my_instance = my_class<std::string>("my value");
my_function(my_instance);

但是我想实现的是这样的函数调用:

my_function("my value")

我的 class 模板应该为我隐式转换为模板类型。我想我需要某种运算符重载。

例如,

std:optional 可以这样做。

您必须添加接受类型可转换为您的 T 的构造函数。

C++20 之前的“经典”方法是使用 SFINAE 和 std::enable_if:

template <typename T>
class my_class
{
public:
   template <typename U, typename = std::enable_if_t<std::is_constructible_v<T,U>>>
   my_class(U&& arg) : my_Value(std::forward<U>(arg)) 
   {}

...

Demo


使用最新标准 (C++20),您可以使用概念并简化您的代码:

template <typename T>
class my_class
{
public:
   template <typename U>
   my_class(U&& arg) requires(std::is_constructible_v<T,U>) 
      : my_Value(std::forward<U>(arg)) 
   {}

...

或者更简单:

template <typename T, typename U>
concept constructible_to = std::constructible_from<U, T>;

template <typename T>
class my_class
{
public:
   template <constructible_to<T> U>
   my_class(U&& arg)
      : my_Value(std::forward<U>(arg)) 
   {}
...

您只能进行一次隐式用户转化,因此您对 const char* 的调用无效。

有几个选项,

  • 为my_class添加另一个构造函数

    my_class(T value) : my_Value(value) {}
    
    template <typename U, std::enable_if_t<std::is_convertible<U, T>, int> = 0>
    my_class(U value) : my_Value(value) {}
    
  • 为 my_function、

    添加重载
    void my_function(my_class<std::string> my_string)
    void my_function(const char* s) { return my_function(my_class<std::string>{s}); }
    
  • 更改调用站点以使用 std::string:

    调用它
    my_function(std::string("my value"))
    
    using namespace std::string_literals;
    my_function("my value"s)
    

问题描述如下:

Implicit conversions - cppreference.com

Order of the conversions

Implicit conversion sequence consists of the following, in this order:

  1. zero or one standard conversion sequence;

  2. zero or one user-defined conversion;

  3. zero or one standard conversion sequence.

When considering the argument to a constructor or to a user-defined conversion function, only a standard conversion sequence is allowed (otherwise user-defined conversions could be effectively chained). When converting from one built-in type to another built-in type, only a standard conversion sequence is allowed.

您当前的代码需要两个隐式用户定义的转换链:从 const char *std::string,然后从 std::stringmy_class<std::string>

要解决这个问题,你必须减少这条链。所以基本上你需要提供构造函数,它允许将字符串文字转换为你的 my_class<std::string>.

PiotrNycz已提供解决方案:

template <class T>
class my_class
{
public:
    my_class(const T& value)
        : my_Value(value)
    {
    }

   template <typename U, typename = std::enable_if_t<std::is_constructible_v<T,U>>>
   my_class(U&& arg) : my_Value(std::forward<U>(arg)) 
   {}

private:
    T my_Value;
};

Demo

正如其他人已经解释的那样,您的问题是您希望连续进行两次隐式转换(字符串文字 (char const*) => std::string => my_class<std::string>)而只允许一个。

已经解释了如何将此链减少为一条的几种方法,但还有一种方法:只需将 std::string 直接传递给您的函数而不是字符串文字

using namespace std::string_literals;
my_function("my value"s);

注意 s 从字符串文字创建 std::string。您需要使用该命名空间才能访问它。