3

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

Fred
  • 596
  • 1
  • 6
  • 19
  • i don't have an explanation on why this is not working, need to check c++ standard for that, but there are other ways to write this if you want – Raxvan Dec 07 '16 at 08:54
  • 1
    Possible duplicate of [Partial ordering with function template having undeduced context](http://stackoverflow.com/questions/1180325/partial-ordering-with-function-template-having-undeduced-context) – Edgar Rokjān Dec 07 '16 at 08:55
  • 2 reason, it's non-deduced context, even if it can deduced, the type is always void – Danh Dec 07 '16 at 08:57
  • @Raxvan: well, could you please tell me the other ways? – Fred Dec 07 '16 at 08:59
  • @Danh: well, then none of the call should work. The 'wstring' and 'bool' ones are compiling ! – Fred Dec 07 '16 at 09:00
  • in `std::enable_if< std::is_integral< T >::value >::type` T cannot be deduced. – Jarod42 Dec 07 '16 at 09:01
  • @all: well ok! But how can I solve this problem? – Fred Dec 07 '16 at 09:05
  • I believe none of those call should work, since `static_assert( false, "SetAttribute: wrong type!" );` doesn't depend on template params – Danh Dec 07 '16 at 09:05
  • @Fred use two structs for `invalid` and `integrals` with static functions for implementations, then use `std::conditional` in `SetAttribute` to choose which one you want. http://en.cppreference.com/w/cpp/types/conditional – Raxvan Dec 07 '16 at 09:21

1 Answers1

1

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..

Marco A.
  • 43,032
  • 26
  • 132
  • 246