К сожалению, UFCS не попал в C ++ 17, и это оставило меня с повторяющейся проблемой:
Иногда я хочу дать типам дополнительную функциональность, используя синтаксис вызова метода (без написания глобальных функций). Это особенно пригодится при работе с монадами.
Я вижу два варианта: один — наследование, а другой — инкапсуляция. Поскольку вы не можете безопасно наследовать от контейнеров STL, это оставляет инкапсуляцию. Например, я хочу продлить std::optional
так я и пишу:
template <typename T>
struct myoption {
// Some functionality
private:
std::optional<T> impl;
};
Моя проблема в том, что каждый раз, когда я хочу сделать это, мне нужно написать все конструкторы (и необходимые методы, которые вы можете использовать с исходным типом, например, push_back
для векторов) оригинальный тип имеет. Даже в более простом контейнере, например, в дополнительном, есть 9 конструкторов. Используя наследование, я могу просто «наследовать» методы и конструкторы суперкласса. Есть ли способ сделать это проще с помощью инкапсуляции?
Я бы реализовал это с помощью частного наследования:
#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
}
Таким образом, вы можете убедиться, что не можете создавать объекты с динамический тип My_vector
и уменьшите усилия, чтобы сделать наследуемые методы доступными с помощью простого макроса (или с помощью директивы) вместо создания прямых функций для каждой функции-члена и перегрузки.
Других решений пока нет …