ПРИМЕЧАНИЕ. НЕ предлагайте мне реализовать перегруженные функции! Я знаю, как это сделать. Цель этого упражнения — научиться работать с шаблонами.
У меня есть эта функция (она принимает некоторые параметры и возвращает вектор шаблонного типа). Поскольку вектор содержит шаблонный тип, а он может меняться в зависимости от вызывающего объекта, метод 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
)?
Начиная с 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 {
/*...*/
}
}
Спасибо вам большое за это. это решило проблему.
@ConfusedCpp Всегда пожалуйста! Я рад, что это помогло.
Однако я не понимаю, почему компилятор оценивает это во время компиляции?
В простом if..else
обе ветви должны быть правильно сформированы, даже если нет возможности выполнения одной из них во время выполнения. Компилятору не требуется удалять мертвую ветвь при использовании константы времени компиляции в выражении if
.
как я могу написать что-то подобное (которое фактически компилируется и запускается) для оператора if, что если тип шаблона является строкой, он делает одно, а если тип int, он делает что-то другое?
Для того, что вы пытаетесь использовать, вам нужно использовать либо:
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 {
...
}
}
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, а не просто то, что он мне нужен.
Во 2-м
if
, наверное, лучше использоватьstd::is_convertible_v<int, T>
вместоstd::is_same_v<T, int>
.