Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the advantage of std::enable_if over static_assert for class templates?

I was wondering about the advantage of std::enable_if over static_asserts to prevent template instantiation. This answer suggests, that std::enable_if allows SFINAE, which is a convincing argument in the case of function templates.

However is this argument legitimate for class templates (and variable templates)? As far as I know, there is no overload resolution involved there, making SFINAE - again, as far as I know - not relevant, but I might be wrong. If so, can you name an example?

If not, I assume static_assert to be the better solution for the given issue (preventing template instantiation) in the case of class templates, since it's arguably more explicit, concise and readable and allows a custom error message. Is that correct or am I missing a point other than SFINAE?

like image 494
Reizo Avatar asked Jan 25 '23 18:01

Reizo


2 Answers

Handling a few distinct types can be done with specialising as you said:

template <class>
class foo;

template <>
class foo <int> { /* int implementation */ };

template <>
class foo <char> { /* char implementation */ };

Now consider that we want to specialise multiple types, and we want float and double to be in the same specialisation. We can't do this without SFINAE, so to avoid repeating the implementation we use inheritance:

class foo_fp_implementation {
    /* specialise for all floating point */ 
};

template <>
class foo <float> : foo_fp_implementation {};

template <>
class foo <double> : foo_fp_implementation {};

So far we've avoided SFINAE, but what if you want a specialisation that takes all types with a certain interface? Example: has method int bar ()? We could try to use the above trick and list all the possible types, but what if there are too many to maintain, or you want it to be usable by others who may use their own types. Here SFINAE comes to the rescue:

template <class, class = int>
class foo;

template <class T>
class foo <T, decltype(T().bar())> {
    // implement using bar interface
};

// other specialisations...

In the above situation, static_assert simply couldn't help.


In conclusion, SFINAE helps to specialise based off exact behaviour rather than exact types.

like image 172
Elliott Avatar answered Apr 06 '23 11:04

Elliott


However is this argument legitimate for class templates (and variable templates)? As far as I know, there is no overload resolution involved there, making SFINAE - again, as far as I know - not relevant, but I might be wrong. If so, can you name an example?

You can specialise class templates and SFINAE may be used to pick between specialisations. It will also prevent instantiation of such (by then, possibly ill-formed) class / its specialisation, instead of failing to compile due to static_assert.

like image 31
Fureeish Avatar answered Apr 06 '23 09:04

Fureeish