Прежде всего: вы будете кричать " XY проблема !"и вы будете правы, но сейчас я пытаюсь увидеть, есть ли хорошее решение для этого конкретного Y, чтобы судить / минимизировать его компромиссы по сравнению с другими Y для этого (большого) X.
Рассмотрим следующий класс шаблона переменных, который наследует от всех своих аргументов шаблона и предоставляет оператор преобразования для их подмножества:
template <typename... Ts>
struct derived : Ts...
{
template<class... SubTs>
operator const derived<SubTs...>()
{
return { static_cast<SubTs>(*this)... };
}
};
Это позволяет вам сделать что-то вроде этого:
struct A { int a; };
struct B { double b; };
struct C { std::unique_ptr<int> c; };
using ABC = derived<A, B, C>;
int foo(const derived<A, B>& in)
{
return in.a + in.b;
}
int test()
{
ABC abc{ {1}, {3.0}, {std::make_unique<int>(4)}};
return foo(x);
}
Преобразование создает временную копию для передачи функциям.Таким образом, вы не можете сделать следующее, потому что unique_ptr
не может быть скопировано:
int bar(const derived<A, C>& in)
{
return in.a + *in.c;
}
int test()
{
ABC abc { {1}, {3.0}, {std::make_unique<int>(4)}};
return bar(x);
}
Живой код: https://godbolt.org/z/KBoBDl
Есть ли решение, где:
Я могу передать не копируемое derived
(без отказа от владения, конечно).
Мне не нужно указывать, какой из A
/ B
/ C
данный член in
из (нет in.get<A>().a
).«Использовать композицию вместо наследования» также не является решением † .Другими словами, семантика in.a
(in->a
также будет в порядке) должна быть сохранена.
Аргументы функции для foo
и bar
прописывают суб-типы, доступные в их телах в едином списке вариационных шаблонов (не обязательно должны быть в derived
, хотя я чувствую, что предыдущее требование форсирует это).Если я не упомяну B
, то функция не должна иметь доступа к B
членам (даже если переданный в derived
содержит B
).
Изменение foo
/ bar
на функции шаблона будет неудачей, но допустимо.Обратите внимание, что template<class T> int foo(T in)
(и удаление оператора преобразования) нарушает последнее требование.Также обратите внимание, что я нахожусь на C ++ 17, поэтому понятия не имею.
В идеале я хотел бы представить сигнатуру функции, чтобы она выглядела как int bar(derived_view<A, C> in)
, но я не вижу, как объединить это со всеми требованиями,Приветствуются частичные идеи / решения, может быть, это поможет.
† derived
- мой лучший способ создания различных вариаций, A
/ B
/ C
уже все структуры-обёртки.Вот почему не должно быть никаких дополнительных указаний на доступ к фактическим данным.
Да, я знаю, "это звучит как нормальные параметры функции с дополнительными шагами!" , но у меня есть множество foo
и bar
, которые принимают множество различных подмножеств из десятков структур A
/ B
/ C
и т. д., каждая из которых строит больше таких структур.Простые функциональные параметры являются хорошо изученным статус-кво и не являются удовлетворительным решением.