12

Sadly, UFCS did not make it into C++17 and that left me with a recurring problem: Sometimes I want to give types extra functionality using the method call syntax (without writing global functions). That would especially come handy when dealing with monads.

I see two options: One is inheritance, and the other is encapsulation. Because you cannot safely inherit from STL containers, that leaves encapsulation. For example, I want to extend std::optional, so I write:

template <typename T>
struct myoption {
    // Some functionality
private:
    std::optional<T> impl;
};

My problem is that every time I want to do this, I basically have to write all the constructors (and needed methods that you can use with the original type, like push_back for vectors) the original type has. Even a simpler container, like optional has 9 constructors. When using inheritance, I can simply 'inherit' the methods and constructors of a super-class. Is there a way to make this easier using encapsulation?

Peter Lenkefi
  • 1,306
  • 11
  • 29
  • 1
    Using encapsulation, you not only have to define all constructors. If the encapsulated class provides methods, your wrapper class has to define them also (if they are relevant for your intended usage). In case of `std::optional`, there are only a few operators and methods but other `std` classes have much more... – Scheff's Cat Oct 31 '17 at 18:38
  • @Scheff Yes, that is what I meant by `and needed methods`. – Peter Lenkefi Oct 31 '17 at 18:39
  • It seems that I skipped reading the text in parentheses. Sorry. – Scheff's Cat Oct 31 '17 at 18:42
  • @Scheff No, actually my sentence is ambiguous, I'll fix it. – Peter Lenkefi Oct 31 '17 at 18:43
  • `operator.()` would presumably be another way to do this, though I imagine its chances of getting in are as up-in-the-air as UFCS. – underscore_d Oct 31 '17 at 22:35

1 Answers1

7

I would implement it by using private inheritance:

#define MAKE_PUBLIC(method) using std::vector<T>::method

template <typename T>
struct My_vector : private std::vector<T> {
    MAKE_PUBLIC(push_back);
    MAKE_PUBLIC(pop_back);
};

int main() {
    My_vector<int> v;
    v.push_back(3);
    std::vector<int>* vec = new My_vector<int>; // won't compile
}

This way, you can make sure that you cannot create objects with dynamic type of My_vector and reduce the effort to make inherited methods accessible by a mere macro (or using directive) instead of creating forward functions for each member function and overload.

Jodocus
  • 7,493
  • 1
  • 29
  • 45