Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable member function using boolean template parameter?

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?

like image 914
Jon Deaton Avatar asked Mar 07 '23 07:03

Jon Deaton


2 Answers

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 */ } 
like image 142
songyuanyao Avatar answered Apr 26 '23 09:04

songyuanyao


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>{});
        }
    };
    
like image 30
Jarod42 Avatar answered Apr 26 '23 10:04

Jarod42