Search code examples
c++templatestemplate-specializationpartial-specialization

c++ template specialization with std::enable_if not working


I've a simple primary function template that I want to partially specialize.

template< typename T >
void SetAttribute( const T& value )
{
  static_assert( false, "SetAttribute: wrong type!" );
}

template<> void SetAttribute( const bool& value ) {}

template<> void SetAttribute( const std::wstring& value ) {}

template< typename T >
void SetAttribute( const typename std::enable_if< std::is_integral< T >::value >::type& value ) {}

int main()
{
  SetAttribute( std::wstring( L"bla" ) );
  SetAttribute( bool( true ) );
  SetAttribute( std::uint32_t( 1 ) ); // error C2338: SetAttribute: wrong type!

  return 0;
}

When I compile this with VS 2015 Update 3, then I'll get an error on the 3d call (see comment). why? I don't understand why the 3d specialization is not used.

Thx Fred


Solution

  • The problem is that you're using T in a non-deduced context

    template< typename T >
    void SetAttribute( const typename std::enable_if< std::is_integral< T >::value >::type& value ) {}
                                                                        ^
    

    Functions are probably the wrong tool for this job (they cannot be partially specialized), a possible workaround if you insist in using functions could be a combination of tag dispatching and specializations

    template<class T>
    void SetAttribute(const T&, std::true_type) {}
    
    template<class T>
    void SetAttribute(const T& value, std::false_type)
    {
      static_assert(std::is_integral<T>::value, "SetAttribute: wrong type!");
    }
    
    template< typename T >
    void SetAttribute(const T& value)
    {
      SetAttribute(value, std::is_integral<T>());
    }
    
    template<> void SetAttribute(const bool&) {}
    
    template<> void SetAttribute(const std::wstring&) {}
    

    Example

    Quite unreadable if you ask me..