mardi 27 juillet 2021

Check if << operator is applicable in overriding template context

I have made a AnyType class which is similar to std::any in C++14. I would like to override the << operator to easily print the content of the stored variable:

std::ostream& operator<<( std::ostream& o, const AnyType& v ) {
  if( v._varPtr_ != nullptr ) v._varPtr_->writeToStream(o);
  return o;
}

And the writeToStream() is an overrided function defined in a PlaceHolder class which is holding the actual typed variable. It is defined as:

void writeToStream(std::ostream& o) const override { o << _variable_; }

My problem is when I define a AnyType object which is holding a variable type with no operator<< overrided, the compiler is throwing an (expected) error while unfolding a defined template class:

error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'const TGraph')
    void writeToStream(std::ostream& o) const override { o << _variable_; }
                                                         ~ ^  ~~~~~~~~~~

Here is a minimal example:

struct PlaceHolder{
  virtual ~PlaceHolder() = default;
  virtual void writeToStream(std::ostream& o) const = 0;
};

template<typename VariableType> struct VariableHolder: public PlaceHolder{
  explicit VariableHolder(VariableType value_) : _variable_(std::move(value_)){  }
  void writeToStream(std::ostream& o) const override { o << _variable_; }

  VariableType _variable_;
};

class AnyType{
public:
  AnyType(){}
  template<typename ValueType> inline void setValue(const ValueType& value_){ 
    _varPtr_ = std::shared_ptr<VariableHolder<ValueType>>(new VariableHolder<ValueType>(value_)); 
  }
  friend std::ostream& operator<<( std::ostream& o, const AnyType& v ) {
    if( v._varPtr_ != nullptr ) v._varPtr_->writeToStream(o);
    return o;
  }

private:
  std::shared_ptr<PlaceHolder> _varPtr_{nullptr};
};

int main(){

  AnyType a;
  a.setValue(int(14));
  std::cout << a << std::endl; // this will work

  // If the following line is uncommented, the compiler will throw an error
  // a.setValue(TGraph()); // this is a CERN's ROOT class
  

}

So my question is: Is there any way to make the compiler check if it is possible to override << before having it explicilty ? This way I could let the writeToStream method to be defined as default: = 0.

May be there is another workarround. Typically this problem does not appear with std::any. Does anyone knows how it is implemented in the std library?

Cheers :)

Aucun commentaire:

Enregistrer un commentaire