there is some class:

template< typename T, typename = typename std::enable_if< std::is_arithmetic<T>::value || std::is_same<T, std::string>::value>::type> class NBTTag { public: ... std::vector<char> toBuffer() const noexcept { std::size_t alignment = 0; std::vector<char> buffer{}; ... alignment = setValueToBuffer(buffer, alignment); return buffer; } std::size_t setValueToBuffer(std::vector<char>& buffer, std::size_t alignment, typename std::enable_if<std::is_arithmetic<T>::value, std::size_t>::type* = nullptr) const noexcept { ... } std::size_t setValueToBuffer(std::vector<char>& buffer, std::size_t alignment, typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type* = nullptr) const noexcept { ... } }; 

I want to make it so that when a numeric type comes into a template class, the first version of the overload would be called, and when std :: string is the second option, but I’ve been fighting this for the second hour ... At the moment I get the following error:

 Error C2061 syntax error: identifier 'type' Error C2061 syntax error: identifier 'type' Error C2039 'type': is not a member of 'std::enable_if<false,std::string>' Error C2039 'type': is not a member of 'std::enable_if<false,size_t>' 

Can someone tell me how to implement this more elegantly?

    1 answer 1

    For the behavior you need, enable_if should be used in conjunction with type inference. If you need a minimum of changes, you can do this:

     template<typename U = T> std::size_t setValueToBuffer(std::vector<char>& buffer, std::size_t alignment, typename std::enable_if<std::is_arithmetic<U>::value, std::size_t>::type* = nullptr) const noexcept { static_assert(std::is_same<T, U>::value, "wrong types"); //... } template<typename U = T> std::size_t setValueToBuffer(std::vector<char>& buffer, std::size_t alignment, typename std::enable_if<std::is_same<U, std::string>::value, std::string>::type* = nullptr) const noexcept { static_assert(std::is_same<T, U>::value, "wrong types"); //... } 

    UPD 01:
    It may be worthwhile to render the setValueToBuffer functionality into a separate structure template and specialize it for the necessary types.

     namespace details { template<typename T> struct SetValueToBufferAux;//Общий шаблон не определяется }//end of namespace details template<typename T, typename = typename std::enable_if< std::is_arithmetic<T>::value || std::is_same<T, std::string>::value>::type> class NBTTag { //Вам точно нужен enable_if в параметрах шаблона класса? //Если нет, то можно поменять на static_assert: //static_assert(std::is_arithmetic<T>::value || std::is_same<T, std::string>::value, "wrong type"); public: //... std::size_t setValueToBuffer(std::vector<char>& buffer, std::size_t alignment) const noexcept { return details::SetValueToBufferAux<T>()(*this, buffer, alignment);//Просто делегируем вызов } private: friend class details::SetValueToBufferAux<T>;//Если SetValueToBufferAux должен иметь доступ к приватным членам }; //Специализации SetValueToBufferAux для нужных типов namespace details { template<> struct SetValueToBufferAux<int> { std::size_t operator() (NBTTag<int> const & tag, std::vector<char>& buffer, std::size_t alignment) const noexcept { //... return 0; } }; template<> struct SetValueToBufferAux<std::string> { std::size_t operator() (NBTTag<std::string> const & tag, std::vector<char>& buffer, std::size_t alignment) const noexcept { //... return 0; } }; //Если нужно добавить другой тип, то просто пишем нужную специализацию. }//end of namespace details 

    UPD 02:
    The code above will force you to write specializations for EVERY type used, for example, for EVERY arithmetic type you will need to provide a specialization SetValueToBufferAux . I consider this unacceptable for this case. You can modify SetValueToBufferAux as follows:

     namespace details { //Добавляем дополнительный параметр заданный по-умолчанию template<typename T, typename = void> struct SetValueToBufferAux; }//end of namespace details //Класс NBTTag остается неизменным namespace details { //Специализация для арифметических типов template<typename T> struct SetValueToBufferAux<T, typename std::enable_if<std::is_arithmetic<T>::value>::type> { std::size_t operator() (NBTTag<T> const & tag, std::vector<char>& buffer, std::size_t alignment) const noexcept { //... } }; //Специализация для отдельного типа template<> struct SetValueToBufferAux<std::string> { std::size_t operator() (NBTTag<std::string> const & tag, std::vector<char>& buffer, std::size_t alignment) const noexcept { //... } }; }//end of namespace details 
    • one
      And if not at least? What is the best option here? - QuickDzen
    • one
      @QuickDzen I don’t know the best, but for rework you need to know the requirements for this method and what possibilities we have. 1) Does he need access to private members of NBTTag? 2) Versions for int and string are mutually exclusive and cannot coexist? 3) Is it possible to introduce additional entities? 4) Available if constexpr from C ++ 17? - Croessmah