Search code examples
c++templatesc++17friend-functionclass-template

How to create a friend function for template base class with constexpr


I want to create a overloaded operator<< for a template base class, that calls the toString function for the child class. The issue is that the toString function of the child class is constexpr, which mean I cannot make it a virtual function of the base class. Here is what I want to do:

template<typename T>
class Base {
public:
  Base(const T& t) : m_val(t) {}
  friend std::ostream & operator<<(std::ostream &os, const Base& base);
protected:
  const T m_val;
};

class Child1 : public Base<SomeLiteralType1> {
public:
  using Base::Base;
  constexpr const char* toString() {
    const char* LUT[] = {"aa", "bb"};
    return LUT[m_val];  // <-- assume T can be converted to int
  }
};

class Child2 : public Base<SomeLiteralType2> {
...
};

std::ostream & operator<<(std::ostream &os, const Base& base) {
  // cannot access toString() since it is not defined in Base
  // maybe using dynamic_cast?
}

int main() {
  Child1 c1 = {...};
  Child2 c2 = {...};
  // I want to be able to use << directly:
  std::cout<<c1<<std::endl;
  std::cout<<c2<<std::endl;
}

Solution

  • Use CRTP to get access to the derived class:

    template <typename T, typename Derived>
    class Base {
      ...
    
      friend std::ostream& operator<<(std::ostream& os, const Base& base) {
        return os << static_cast<const Derived&>(base).toString();
      }
    
      ...
    };
    
    class Child1 : public Base<int, Child1> {
      ...
    };
    

    Compiler Explorer