I would like a class to have two different implementations of push, and choose based on a boolean template argument. I tried using the SFINAE principle as described in this answer, like so:
template<class T, bool foo=true>
class Bar {
  template <>
  typename std::enable_if<foo>::type
  push(const T& value) { /* one implementation */}
  template <>
  typename std::enable_if<!foo>::type
  push(const T& value) { /* another implementation */ } 
}
however, I am getting an error of "cannot specialize a function push within class scope" under gcc, and I do not understand why. Although my code is not exactly like that in the linked answer, it seems very similar and I can't spot the critical difference.
I also tried using a syntax similar to that suggested in this answer but it is also not working (the error is "class member cannot be redeclared" instead):
  template <bool enable=foo>
  typename std::enable_if<enable>::type
  push(const T& value) { /* one implementation */}
  template <bool enable=!foo>
  typename std::enable_if<enable>::type
  push(const T& value) { /* another implementation */ } 
How can I accomplish this?
Firstly, SFINAE works with function templates overloading; so you should go with the 2nd approach. But you declare two overloads with same signature; note that the default argument of template parameter doesn't belong to the signature.
Change it to
template <bool enable=foo>
typename std::enable_if<enable>::type
//                      ~~~~~~
push(const T& value) { /* one implementation */}
template <bool enable=foo>
typename std::enable_if<!enable>::type
//                      ~~~~~~~
push(const T& value) { /* another implementation */ } 
                        As alternatives:
if constexpr in C++17:
template<class T, bool foo=true>
class Bar {
public:
    void push(const T& value) {
        if constexpr(foo) {
            /* one implementation */
        } else {
            /* another implementation */
        }
    }
};
Tag dispatching:
template<class T, bool foo=true>
class Bar {
    void push_impl(const T& value, std::true_type) {
        /* one implementation */
    } 
    void push_impl(const T& value, std::false_type) {
        /* another implementation */
    }
public:
    void push(const T& value) {
        push_impl(value, std::integral_constant<bool, foo>{});
    }
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With