9

I want to implement a private function based on a boolean template parameter. Something like that:

#include <iostream>

using namespace std;

template <bool is_enabled = true>
class Aggregator {
public:
    void fun(int a) {
        funInternal(a);
    }

private:
    void funInternal(int a, typename std::enable_if<is_enabled>::type* = 0) {
        std::cout << "Feature is enabled!" << std::endl;
    }

    void funInternal(int a, typename std::enable_if<!is_enabled>::type* = 0) {
        std::cout << "Feature is disabled!" << std::endl;
    }
};

int main()
{
   Aggregator<true> a1;
   Aggregator<false> a2;

   a1.fun(5);
   a2.fun(5);

   return 0;
}

But the program above does not compile: error: no type named 'type' in 'struct std::enable_if' void funInternal(int a, typename std::enable_if::type* = 0).

Is it possible to realize the desired behavior with enable_if?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
moo
  • 486
  • 8
  • 22
  • 3
    Without saying why, I can say this is probably the most minimal you can make the changes to your code: http://coliru.stacked-crooked.com/a/480dd15245cdbb6f – chris Mar 12 '15 at 04:10
  • Ah, so the trick is to create a method parameter from the class template parameter? – moo Mar 12 '15 at 04:13
  • 2
    I think it works for the same reason as this: https://www.youtube.com/watch?v=dTeKf5Oek2c&t=2244 – chris Mar 12 '15 at 04:18
  • @chris If I'm not mistaken, in the OP the overload is based on a _value_ (i.e., a non-type template parameter) whereas that video is overloading for different types. Do you think it should still work regardless of this detail? – James Adkison Mar 12 '15 at 05:48
  • @JamesAdkison, It's a bit different, but the value becomes the first argument to `std::enable_if`. Applying the same logic, the user could call `a1.fun(5)` and things would change, just like the normal usage of `std::enable_if`. – chris Mar 12 '15 at 05:55
  • @chris `a1.fun(5)` cannot work because that function is not templated. Am I misunderstanding your point? – James Adkison Mar 12 '15 at 06:03
  • @JamesAdkison, My bad, I meant to say `funInternal` could be called with a different template argument than the default (in the Coliru link, so `funInternal(5)`), and while it's only ever called from inside the class, with the default template argument, I don't think the checking extends that far. Disclaimer: I'm really fuzzy past the more basic SFINAE. – chris Mar 12 '15 at 06:06
  • @chris But `funInternal` also isn't templated. – James Adkison Mar 12 '15 at 06:13
  • @JamesAdkison, In my [Coliru link](http://coliru.stacked-crooked.com/a/480dd15245cdbb6f) – chris Mar 12 '15 at 06:16
  • @chris Very neat! I was playing with how to solve this but I couldn't quite figure it out. I don't know how you made that link but I made a small change, see my answer. However, I'm not trying to take credit for your solution and I'll be happy to delete my answer after you've seen it. – James Adkison Mar 12 '15 at 06:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72811/discussion-between-james-adkison-and-chris). – James Adkison Mar 12 '15 at 06:27

1 Answers1

12

The following is an adaptation of the solution (http://coliru.stacked-crooked.com/a/480dd15245cdbb6f) provided by @chris in the comments, which seems to meet your needs.

#include <iostream>

template<bool is_enabled = true>
class Aggregator
{
public:
    void fun(int a)
    {
        funInternal(a);
    }

private:
    template<bool enabled = is_enabled>
    void funInternal(typename std::enable_if<enabled, int>::type a)
    {
        std::cout << "Feature is enabled!" << std::endl;
    }

    template<bool enabled = is_enabled>
    void funInternal(typename std::enable_if<!enabled, int>::type a)
    {
        std::cout << "Feature is disabled!" << std::endl;
    }
};

int main()
{
    Aggregator<true> a1;
    Aggregator<false> a2;

    a1.fun(5);
    a2.fun(5);

    return 0;
}
Community
  • 1
  • 1
James Adkison
  • 9,412
  • 2
  • 29
  • 43