如何使用布尔模板参数启用成员函数?

How to enable member function using boolean template parameter?

我希望 class 有两个不同的 push 实现,并根据布尔模板参数进行选择。我尝试使用 中描述的 SFINAE 原理,像这样:

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 */ } 
}

然而,我在gcc下得到了"cannot specialize a function push within class scope"的错误,我不明白为什么。虽然我的代码与链接答案中的代码不完全一样,但看起来非常相似,我看不出关键的区别。

我也尝试使用类似于 中建议的语法,但它也不起作用(错误是 "class member cannot be redeclared"):

  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 */ } 

我怎样才能做到这一点?

首先,SFINAE使用函数模板重载;所以你应该采用第二种方法。但是您声明了两个具有相同签名的重载;请注意,模板参数的默认参数不属于签名。

改为

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 */ } 

备选方案:

  • if constexpr 在 C++17 中:

    template<class T, bool foo=true>
    class Bar {
    public:
        void push(const T& value) {
            if constexpr(foo) {
                /* one implementation */
            } else {
                /* another implementation */
            }
        }
    };
    
  • 标签调度:

    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>{});
        }
    };