3
votes

I am quite new to std::enable_if and wondering how to use it. I have a template class:

template<int a, int b>
class foo {
}

Now I only want to instantiate it when a + b equals to 10. Could I make this possible using std::enable_if?

The second question: If I have a member in class foo

template<int a, int b>
class foo {
  int c;
}

I only want to have c when

a = 5. 

How do I do that using std::enable_if? Is this one the correct case to use std::enable_if?

4
That's not what enable_if is for. It's only for deduced types in function templates.Kerrek SB
@KerrekSB: Or to disable specializations of class templates. Both have been the core usages of boost::enable_if for a long time and both are still valid use cases. Note that this is usually done in the context of multiple specializations of a base template to select one over the others, rather than just disabling a template altogether.David Rodríguez - dribeas
@DavidRodríguez-dribeas: That's a good point. I've not used it for class template specializations a lot so far...Kerrek SB
Simpler: template<int a> class foo { static const int b = 10 - a;MSalters

4 Answers

12
votes

I guess you can use static_assert better to enforce that constraint instead of enable_if

template<int a, int b>
class foo {
    static_assert(a+b==10, "a+b is not 10");
};

int main()
{
    foo<5,5> f; // will compile
    foo<1,5> f; // will fail to compile with error: a+b is not 10
    return 0;
}

enable_if is primarily used to conditionally remove functions and classes from overload resolution based on type traits and to provide separate function overloads and specializations for different type traits.

13
votes
template<int a, int b, typename T = typename std::enable_if<a + b == 10>::type>
class foo {
};

This should do the job; just make sure you never explicitly provide the third template parameter when instantiating the template.


As others mentioned, static_assert is a much better fit.

4
votes

With C++20

You can achieve that simply by adding requires to the template:

template<int a, int b> requires (a + b == 10)
struct foo {
    int c;
};

int main() {
    foo<3, 7> ok;
    // foo<3, 8> doesnt_compile;
}

The requires clause gets a constant expression that evaluates to true or false deciding thus whether to consider this as a proper match, if the requires clause is true, or ignore it otherwise.

Code: https://godbolt.org/z/yHh4Et

2
votes

Simple, just don't use enable_if

template<bool Ten>
struct Base
{
    int c;
};

template<>
struct Base<false>
{ };

template<int a, int b>
struct foo : Base<a+b == 10>
{
};