is_enum в другом шаблоне функция не работает / компиляция

#c #templates #enums

#c #шаблоны #перечисления

Вопрос:

У меня есть шаблонная функция, которая работает нормально, если я не использую enum тип аргумента as (здесь в сокращенной форме; он преобразует строку в тип anotjer с помощью stringstream s):

 template<typename T>
void section::getVal(std::string key,Tamp; var)
{   
    std::stringstream ss; ss.str(key);
    ss>>var;
}
  

Теперь я хочу, чтобы эта функция работала с любым enum , поэтому я попробовал

 enum slimit {lower,higher,between,nolim};

template<typename T>
void section::getVal(std::string key,Tamp; var)
{   
    std::stringstream ss; 
    ss.str(key);
    if(!std::is_enum<T>::value)
        ss>>var;
    else
    {  
        int h;
        ss>>h;
        var=static_cast<T>(h);
    }
}
  

К сожалению, это не компилируется

 (error: no match for 'operator>>' (operand types are 'std::stringstream {aka std::__cxx11::basic_stringstream<char>}' and 'sensact::slimit')
                ss>>var;)
  

Если я заменяю ss>>var; на что-то, что не заботится о типе ( int n=0; ), он компилируется, и if-различие / is_enum работает отлично, и блок else выполняется, если var это enum тип.

Итак, как я могу заставить ее работать и почему она не компилируется?

Ответ №1:

Хотя if оператор выполняет только одну ветвь, он все равно компилирует все ветви. Поскольку код неверно сформирован в одной из ветвей, вы получаете сообщение об ошибке.

Если вы хотите условно скомпилировать некоторые ветки, вы можете использовать constexpr if так:

 if constexpr (!std::is_enum<T>::value)
   ss >> var;
else
{  
  int h;   // in general, std::underlying_type_t<T> instead of int,
           // to allow for other enumeration types
  ss >> h;
  var=static_cast<T>(h);
}
  

Спасибо @Jarod42 за underlying_type предложение в комментарии.

Комментарии:

1. Хорошо, но в OP нет тега C 17: вы должны указать, что if constexpr это доступно только начиная с C 17.

2. ДА… может быть, пришло время признать, что C 17 (если не C 20) является ответственным.

3. @max66 Да, я пробовал это с парой решений C 20, но несколько пользователей жаловались: p, так что, возможно, пока нет. Но C 17 должен быть принят как минимум 🙂

4. int -> std::underlying_type_t<T> чтобы пойти дальше.

5. @Jarod42 Привет, выглядит отлично, спасибо. Я узнал кое-что новое 🙂