Возвращайте правильный тип, когда шаблон, переданный в аргумент функции, меняет тип

ПРИМЕЧАНИЕ. НЕ предлагайте мне реализовать перегруженные функции! Я знаю, как это сделать. Цель этого упражнения — научиться работать с шаблонами.

У меня есть эта функция (она принимает некоторые параметры и возвращает вектор шаблонного типа). Поскольку вектор содержит шаблонный тип, а он может меняться в зависимости от вызывающего объекта, метод push_back() должен принять правильный тип.

Поэтому я попробовал что-то вроде этого:

template<class T>void foo(int n, vector<T>& vec)
{
   ...
   if (is_same<T, string>::value)
      vec.push_back("");
   else
      vec.push_back(INT_MIN);
}

Я получаю ошибку компиляции в VS C++:

ни одна перегруженная функция не может преобразовать все типы аргументов

Это потому, что в зависимости от того, какого типа шаблон, одна из этих веток имеет неправильный тип (я так понимаю).

Однако я не понимаю, почему компилятор оценивает это во время компиляции? Чтобы проверить, действительно ли ветвь работает (т. е. правильно ли оценивается оператор is_same и работает ли if), я заменил оператор push_back() нейтральным: int j=0;. Я скомпилировал его, запустил, и он работает отлично; другими словами, в зависимости от типа шаблона оценивается первая или вторая ветвь.

Таким образом, мой главный вопрос: как я могу написать что-то подобное (которое на самом деле компилируется и запускается) для утверждения if, что если тип шаблона string, он делает одно, а если тип int, он делает что-то другое? Или, если это действительно единственный способ сделать это, какие флаги я могу включить в компиляторе, чтобы подавить ошибку компиляции (поскольку оператор if работает должным образом и никогда не встретит неверный тип push_back)?

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Начиная с C++17, вы можете использовать constexpr, если:

template <class T>
void foo(int n, std::vector<T>& vec) {
    if constexpr (std::is_same_v<T, std::string>) {
        vec.push_back("");
    } else if constexpr (std::is_same_v<T, int>) {
        vec.push_back(INT_MIN);
    } else {
        /*...*/
    }
}

Во 2-м if, наверное, лучше использовать std::is_convertible_v<int, T> вместо std::is_same_v<T, int>.

Remy Lebeau 18.07.2024 21:04

Спасибо вам большое за это. это решило проблему.

ConfusedCpp 18.07.2024 22:06

@ConfusedCpp Всегда пожалуйста! Я рад, что это помогло.

Ted Lyngmo 18.07.2024 22:36

Однако я не понимаю, почему компилятор оценивает это во время компиляции?

В простом if..else обе ветви должны быть правильно сформированы, даже если нет возможности выполнения одной из них во время выполнения. Компилятору не требуется удалять мертвую ветвь при использовании константы времени компиляции в выражении if.

как я могу написать что-то подобное (которое фактически компилируется и запускается) для оператора if, что если тип шаблона является строкой, он делает одно, а если тип int, он делает что-то другое?

Для того, что вы пытаетесь использовать, вам нужно использовать либо:

  • if-constexpr в C++17 и более поздних версиях, что устраняет мертвую ветку, например:
template<class T>
void foo(int n, vector<T>& vec)
{
   ...
   if constexpr (is_same_v<T, string>) {
      vec.push_back("");
   }
   else if constexpr (is_convertible_v<int, T>) {
      vec.push_back(INT_MIN);
   }
   else {
      ...
   }
}
  • перегрузки функций, используя SFINAE (т.е. std::enable_if), чтобы сообщить компилятору, какие перегрузки доступны для любого заданного типа, например:
template<class T,
         enable_if<is_same<T, string>::value, bool>::type = true>
void foo(int n, vector<T>& vec)
{
   ...
   vec.push_back("");
   ...
}

template<class T,
         enable_if<is_convertible<int, T>::value, bool>::type = true>
void foo(int n, vector<T>& vec)
{
   ...
   vec.push_back(INT_MIN);
   ...
}
  • специализации шаблона, например:
template<class T>
void foo(int n, vector<T>& vec)
{
   ...
}

template<>
void foo<string>(int n, vector<string>& vec)
{
   ...
   vec.push_back("");
   ...
}

template<>
void foo<int>(int n, vector<int>& vec)
{
   ...
   vec.push_back(INT_MIN);
   ...
}

Спасибо тебе за это. это наиболее полное и ясное объяснение того, что происходит за кулисами. это помогло мне понять, почему мне нужен if constexpr, а не просто то, что он мне нужен.

ConfusedCpp 18.07.2024 22:18

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