1

In the following class, wrapper takes a pointer to an arbitrary const method and returns the result of a call to that method with const removed. This can be used to generate the corresponding non-const method...

struct C {
  int x[10];

  int const& get(int i) const { return x[i]; }
  int const& getr(int const& i) const { return x[i]; }

  template<typename T, typename... Ts>
  auto& wrapper(T const& (C::*f)(Ts...) const, Ts... args) {
    return const_cast<T&>((this->*f)(args...));
  }

  int& get(int i) { return wrapper(&C::get, i); }
  int& getr(int const& i) { return wrapper(&C::getr, i); }
};

almost.

The problem is that the final method getr() cannot be compiled, because the argument list passed to wrapper() doesn't imply pass-by-reference. By the time we get inside wrapper() the compiler is looking for a pass-by-value version of getr().

Is there a trick to this?

sh1
  • 3,914
  • 13
  • 28
  • 1
    *Why* are you passing the index by reference? I simply fail to see the reasoning behind it. – Some programmer dude Dec 15 '16 at 09:09
  • On a similar note (and guessing that the code you show is just a simplified version of some actual code) why have the `const` function return *references*? *If* you're not doing anything more advanced with the wrapper and return types, then returning `const&` is not really useful here. And using a wrapper such as this is also making the code more opaque and unmaintainable. – Some programmer dude Dec 15 '16 at 09:16
  • @Someprogrammerdude, some uses of the getter initialise a local reference which they will modify in the context of their work, while other uses of the getter are inside const methods. I could return a pointer, but it works as a reference and I get the never-`NULL` contract. The _actual_ index is a complex data structure, and would have been noise in the context of the question. – sh1 Dec 15 '16 at 09:30

1 Answers1

6

You can perfect forward the arguments to the function:

template<typename T, typename... Ts, typename... Args>
auto& wrapper(T const& (C::*f)(Ts...) const, Args&&... args) {
  return const_cast<T&>((this->*f)(std::forward<Args>(args)...));
}

This is achieved by making args a forwarding reference parameter pack. Note that we need to introduce a new Args template parameter pack in order to deduce the arguments correctly.

Community
  • 1
  • 1
TartanLlama
  • 59,364
  • 11
  • 141
  • 183
  • Hm. Seems to be falling down when I overload `get() const` with an alternative argument list (either no arguments, or a different type). I'll keep fiddling... – sh1 Dec 15 '16 at 10:09