0

I have a functor class that has a member buffer. Due to the semantics, it makes sense that this buffer is mutable. (it is, for example an std::vector that is used for .reserve and .capacity only)

struct F{
   mutable std::vector<double> buffer_;
   double operator(double const&) const{... reuse buffer_ ...;}
};

Used as F f; for(double d = 0; ; ++d) f(d);

Now, if for some reason I have a buffer available when F is constructed, I would like buffer_ to be a reference. The generalized code is

template<class Vector = std::vector<double>> // Vector can be also std::vector<double>&&
struct F{
   mutable Vector buffer_; 
   double operator(double const&) const{... reuse buffer_ ...;}
};

Which I can use as F<std::vector<double>> f; for(...) f(d);.

However I cannot make it work as

std::vector<double> existing buffer;
F<std::vector<double>&> f{existing_buffer}; 
for(...) f(d);

because buffer_ cannot be declared as a ‘mutable’ reference.

(the member would be effectively a forbidden mutable std::vector<double>& buffer_.)

How can I make the code generic when the member is posibly a mutable value but also can be reference?


I could have two specializations of F (one for types and one for references), but I am curious if I can have it one single definition.

template<class Vector = std::vector<double>>
struct F{
    mutable Vector buffer_;
    template<class... Args>
    double operator()(double const& d) const{...}
};

template<class Vector>
struct F<Vector&>{
    Vector& buffer_;
    template<class... Args>
    double operator()(double const& d) const{...}
};

(I think mutable should be ignored for reference types, for generic code.)

alfC
  • 14,261
  • 4
  • 67
  • 118
  • 1
    Maybe [std::reference_wrapper](http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper) could serve helping hand? e.g. [\[like this\]](https://wandbox.org/permlink/Ruuwj8GLl4dcZD1a) – W.F. Jan 18 '18 at 10:10
  • 1
    @W.F., nice formal workaround. It is unfortunate that `reference_wrapper` doesn't wrap better. (all the member functions using the buffer need to be rewritten not to use the `.`dot operator. (e.g. `v.resize()` doesn't work when `v` is a `std::reference_wrapper>`.) – alfC Jan 18 '18 at 10:16
  • yup! missed that... :) – W.F. Jan 18 '18 at 10:17
  • @W.F.. no problem. Your solution works with more modifictions down the road. I got bitten by this before: https://stackoverflow.com/questions/34235818/type-emulating-a-c-reference-better-than-stdreference-wrapper . I think it is a defect in the language, until we have the change to do .dot operator overloads. – alfC Jan 18 '18 at 10:21

1 Answers1

1

Something along these lines, perhaps?

struct F {
  mutable std::vector<double> local_buffer_;
  std::vector<double>& buffer_;

  F() : buffer_(local_buffer_) {}
  F(std::vector<double>& existing_buffer) : buffer_(existing_buffer) {}
};
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • I think the class will be a bit larger than it needs to be but it should work. – alfC Jan 18 '18 at 18:11
  • Another downside is that when copy assigned, `buffer_` would need to be rebound to the new object. (when Vector is not a reference is makes sense to think of F as a value type). – alfC Jan 23 '18 at 00:05