c++templatesmember-functionsspecialization

specializing a member function which has an independent template parameter


I am trying to extend and specialize a member function of the BitStream class from rapidCheck.

template <typename Source>
class BitStream {
public:
  explicit BitStream(Source source);

  /// Returns the next value of the given type with maximum size.
  template <typename T>
  constexpr T next();

  constexpr char next();
};

template <typename Source>
BitStream<Source>::BitStream(Source source)
{}

template <typename Source>
template <typename T>
constexpr T BitStream<Source>::next() {
  return T();
}

template <typename Source>
constexpr char BitStream<Source>::next() { return (char)(1); }

int main() {
    BitStream<int> bs(2);
    static_assert( bs.next<int>() == 0 ); // as expected
    static_assert( bs.next() == 1 );      // not really a specialization
    static_assert( bs.next<char>() == 1 ); // fails, but this should succeed!
}

This simplified snippet compiles, but the last assert fails, since I had not been able to really specialize next() for T=char. How could that be achieved? My requirement here is that I want to be compatible to the rest of rapidcheck, so bs.next<char>() should call the specialized version. Thanks in advance!


Solution

  • You may only specialize a member template in a specialized class template like in the following reduced example:

    template <typename Source>
    class BitStream {
     public:
      explicit BitStream(Source source);
    
      /// Returns the next value of the given type with maximum size.
      template <typename T>
      constexpr T next();
    };
    
    template <>
    template <>
    constexpr char BitStream<int>::next<char>() {
      return 1;
    }
    
    int main() {
      BitStream<int> bs(2);
      static_assert(bs.next<char>() == 1);  // succeeds
    }
    

    Suggestion. Consider implementing a custom std::basic_streambuf instead of BitStream and you will be able to use input streams and input operators like bs >> char_var and bs >> int_var instead of char_var = bs.next<char>() and int_var = bs.next<int>().