Вызов функции с параметром шаблона

Я написал простой шаблон класса:

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")

Мой шаблон класса должен неявно выполнять преобразование в тип шаблона для меня. Я думаю, мне нужна какая-то перегрузка оператора.

std:optional может сделать это, например.

Есть несколько вариантов: добавить еще один конструктор для my_class, добавить перегрузку для my_function, изменить сайт вызова, чтобы вызывать его с помощью std::string.

Jarod42 10.12.2020 14:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
1
138
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы должны добавить конструктор, принимающий конвертируемый тип, в ваш 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)) 
   {}

...

Демо


С новейшим стандартом (С++ 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)
    

Проблема описана здесь:

Неявные конверсии - cppreference.com

Порядок преобразований

Последовательность неявного преобразования состоит из следующего в указанном порядке:

  1. ноль или одна стандартная последовательность преобразования;

  2. ноль или одна пользовательская конверсия;

  3. ноль или одна стандартная последовательность преобразования.

При рассмотрении аргумента конструктора или определяемой пользователем функции преобразования допускается только стандартная последовательность преобразования (в противном случае определяемые пользователем преобразования могут быть эффективно объединены в цепочку). При преобразовании из одного встроенного типа в другой встроенный тип допускается только стандартная последовательность преобразования.

Ваш текущий код требует цепочки из двух неявных определяемых пользователем преобразований: формы const char * в std::string и затем из std::string в my_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;
};

Демо

Как уже объясняли другие, ваша проблема заключается в том, что вы хотите иметь два неявных преобразования подряд (строковый литерал (char const*) => std::string => my_class<std::string>), в то время как разрешено только одно.

Несколько способов сократить эту цепочку до одной уже объяснялись, но есть еще один: просто передать std::string прямо в вашу функцию вместо строкового литерала.

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

Обратите внимание на s, который создает std::string из строкового литерала. Вам нужно использовать это пространство имен, чтобы иметь к нему доступ.

Другие вопросы по теме