Я хочу написать функцию, которая:
Теперь, если бы я хотел 1 + 2, я бы просто использовал gsl::span
, И если бы хотел 1 + 3, я бы использовал owner<T*>
, Но что мне делать, когда я хочу все три? Должен ли я пройти owner<gsl::span<T>>
? Что-то другое?
Одним из вариантов будет определение собственного абстрактного базового класса для инкапсуляции данных. Что-то вроде:
template<typename T>
class DataHolder {
public:
virtual ~DataHolder() = default;
virtual gsl::span<T> get() const = 0;
};
Тогда ваша функция может выглядеть примерно так:
void foo(std::unique_ptr<DataHolder<int>> data) {
if (!data)
return;
for (auto v : data->get())
std::cout << v << " ";
}
Вызывающая сторона может затем реализовать базовый класс с любым контейнером, который они хотят. Там будет небольшая стоимость полимофизма, но не на основе каждого элемента.
Если вы не хотите платить за полиморфизм, возможно, вы могли бы заставить свою функцию принимать параметр шаблона.
template<typename DataHolder>
void foo(DataHolder data) {
for (auto v : data())
std::cout << v << " ";
}
где неявный интерфейс для DataHolder
может быть удовлетворен чем-то вроде:
struct VectorHolder {
std::vector<int> data;
gsl::span<const int> operator()() const { return data; }
};
или если вы действительно не хочу использовать vector
, Вы можете использовать что-то вроде этого (как предложено @utnapistim):
struct ArrayHolder {
std::unique_ptr<int[]> data;
ptrdiff_t length;
gsl::span<const int> operator()() const { return {data.get(), length}; }
};
Других решений пока нет …