template <typename Ret, typename Arg, size_t N>
class Foo {
public:
virtual ~Foo() = default;
virtual Ret bar( вот тут непонятно что написать, но с участием Arg ) = 0;
};
Чтобы пользоваться этим примерно так:
class S3 : public Foo<void, int, 3> {
public:
void bar(int a1, int a2, int a3) override {
}
};
class S5 : public Foo<void, int, 5> {
public:
void bar(int a1, int a2, int a3, int a4, int a5) override {
}
};
Здравствуйте, Dair, Вы писали:
D>Как бы такое написать
D>
D>template <typename Ret, typename Arg, size_t N>
D>class Foo {
D>public:
D> virtual ~Foo() = default;
D> virtual Ret bar( вот тут непонятно что написать, но с участием Arg ) = 0;
D>};
D>
Ret bar(std::array<Arg, 3>) = 0;
bar({1, 2, 3});
D>Чтобы пользоваться этим примерно так:
D>Можно ли?
именно так -- только вручную.
а как с этими a_x предполагается работать?
D>template <typename Ret, typename Arg, size_t N>
D>class Foo {
D>public:
D> virtual ~Foo() = default;
D> virtual Ret bar( вот тут непонятно что написать, но с участием Arg ) = 0;
D>};
D>
D>Чтобы пользоваться этим примерно так: D>
D>class S3 : public Foo<void, int, 3> {
D>public:
D> void bar(int a1, int a2, int a3) override {
D> }
D>};
D>class S5 : public Foo<void, int, 5> {
D>public:
D> void bar(int a1, int a2, int a3, int a4, int a5) override {
D> }
D>};
D>
Здравствуйте, night beast, Вы писали:
NB>а как с этими a_x предполагается работать?
Это синтетический пример, конечно, на практике по-другому выглядит, но всё равно надо генерировать много одинаковых параметров у ObjC-шного block'а (это там так лямбды назвают).
Это я так пишу прослойку для работы из C++ через ObjC с предоставляемым iOS'ом JavaScriptCore.
Из C++ вызов JSных методов сделал влёт, а вот из JS вызывать C++ные влёт не получилось. Но завтра получится, спасибо rg45
При желании можно было бы оформить небольшую утилитку, которая щьет сразу последовательность типов (tuple) вместо последовательности индексов. С другой стороны, я сомневаюсь, что этот инструмент найдет хоть сколько-нибудь широкое применение, тогда как цена всего-то одна лишняя строчка в базаовом классе Foo_.
А что просто указатель на инты и их количество в bar не передать? Один предок, имхо получишь большее удобство пользования полиморфизмом времени исполнения, он же тебе явно нужен, раз ты хочешь виртуальный bar.
Здравствуйте, andyp, Вы писали:
A>А что просто указатель на инты и их количество в bar не передать? Один предок, имхо получишь большее удобство пользования полиморфизмом времени исполнения, он же тебе явно нужен, раз ты хочешь виртуальный bar.
Тогда ему пришлось бы в рантайме контролировать число переданных фактических параметров. Организовывать диспетчеризацию и обрабатывать ошибки, которые мог бы предотвратить компилятор. Где же тут удобство? И удобств меньше и качество кода страдает.
R>Тогда ему в рантайме придется еще и проверять правильность количества переданных фактических параметров. Меньшее количество предков не означает автоматически большее удобство. Так ведь можно же и вместо указателя на инты использовать void* и получить вообще одного общего предка.
Если о крайностях, то почему просто void*? Три точки же — variadic virtual function
Если нужен "полиморфизм" по числу аргументов, то явно проверять не надо. Каждый производный класс просто обрабатывает свое число параметров, перегрузив bar
Здравствуйте, andyp, Вы писали:
A>Если нужен "полиморфизм" по числу аргументов, то явно проверять не надо. Каждый производный класс просто обрабатывает свое число параметров, перегрузив bar
И как себя должна повести функция, ожидающая три параметра, которой передали два?
A>Но, может, я как обычно все не так понял.
Речь о том, что незачем переносить в рантайм потенциальные проблемы, которые можно предотвратить при помощи компилятора.
Здравствуйте, rg45, Вы писали:
R>И как себя должна повести функция, ожидающая три параметра, которой передали два?
Да черт его знает, от приложения зависит. Например, сказать "Не мое" и выйти?
A>>Но, может, я как обычно все не так понял.
R>Речь о том, что незачем переносить в рантайм потенциальные проблемы, которые можно предотвратить при помощи компилятора.
Да я не против помощи компилятора. Просто мне не очень понятен способ использования этой горы сгенерированных интерфейсов с одинаковыми именами, может поэтому и пишу не про то.
Здравствуйте, andyp, Вы писали:
R>>И как себя должна повести функция, ожидающая три параметра, которой передали два? A>Да черт его знает, от приложения зависит. Например, сказать "Не мое" и выйти?
Главным остается то, что как-то это проблему нужно решать все-таки. Тогда как ее могло бы просто не быть.
A>Да я не против помощи компилятора. Просто мне не очень понятен способ использования этой горы сгенерированных интерфейсов с одинаковыми именами, может поэтому и пишу не про то.
Ну то, что использование не очень понятно, это и не удивительно — ТС ведь прямо сказал, что пример синтетический.
Давай пробежимся от начала по основным моментам? Исходное положение: есть набор независимых иерархий классов. Базовые классы этих иерархий хоть и независимы друг от друга, но имеют очень похожий вид. Что у ТС вызывает, имхо, вполне естественное желание описать все эти независимые базовые классы при помощи единого шаблона. Ты предлагаешь альтернативный подход — объединить эти иерархии таким образом, что функции, изначально имеющие разное число формальных параметров, начинают иметь одинаковую сигнатуру и представлются одной и той же виртуальной функцией в объединенном базовом классе. Таким образом, число переданных фактических параметров уходит из-под контроля компилятора и становится заботой самих этих функций.
Здравствуйте, rg45, Вы писали:
R>Ты предлагаешь альтернативный подход — объединить ранее независимые базовые классы таким образом, что функции, изначально имеющие разное число формальных параметров начинают иметь одинаковую сигнатуру и представлются одной и той же виртуальной функцией в базовом классе. Таким образом, число переданных фактических параметров уходит из-под контроля компилятора и становится заботой самих этих функций.
Не то что именно это предлагаю. Не зная как это будет использоваться, трудно что-то уж прям предлагать.
Можно ж например сделать bar невиртуальным шаблоном, требуемое количество аргументов хранить в базовом классе, там проверять, и уже потом звать виртуальный метод потомка. Такой вот NVI.
Всего лишь призывал ТС на другие варианты именно дизайна всего этого посмотреть.
Здравствуйте, andyp, Вы писали:
A>Можно ж например сделать bar невиртуальным шаблоном, требуемое количество аргументов хранить в базовом классе, там проверять, и уже потом звать виртуальный метод потомка. Такой вот NVI.
Можно. Получится эдакий элегантный вариант самодельной диспетчеризации, о которой я упоминал здесь
. Но при всей элегантности, проверка соответствия числа формальных и фактических параметров обеспечивается программистом и выполняется в рантайме. Отбираем хлеб у компилятора.
Здравствуйте, ArtDenis, Вы писали:
AD>Для этого больше подходит препроцессор (например BOOST_PP_ENUM_PARAMS), а не шаблоны
AD>Хотя... с std::index_sequence, предложенный выше, вполне себе вариант
Я еще могу согласиться с тем, что этот способ более привычен (и то с натяжкой). Но вот насчет того, что он лучше — никак. Судите сами, нам так или иначе придется определить макрос содержащий в себе болванку базового класса. Потом нам нужно будет как-то это определение растиражировать — либо вручную, либо при помощи все того же препроцессора (BOOST_PP_REPEAT_). Причем, отдельно для каждого типа параметра в отдельности (не забываем, что среди параметров шаблона Foo, помимо "size_t N", есть еще "typename Arg") — так что по-любому без ручной копипасты не обойтись. В результате вместо шаблона мы получаем то же самое определение, только помещенное внутрь монстровидного макроса, с BOOST_PP_ENUM_PARAMS и кучей слешей. Плюс фиксированное количество воплощений, которое практически наверняка будет и избыточным и недостаточным одновременно (избыточным по поддерживаемому числу параметров и потенциально недостаточным по типу аргумента). Ну и плюс сам факт использования макросов. Так чем же это лучше?
Здравствуйте, rg45, Вы писали:
R>Я еще могу согласиться с тем, что этот способ более привычен (и то с натяжкой). ... Ну и плюс сам факт использования макросов. Так чем же это лучше?
Вот именно что привычен. Такой код будет проще поддерживать сиплюплюсникам старой закалки
Здравствуйте, ArtDenis, Вы писали:
R>>Я еще могу согласиться с тем, что этот способ более привычен (и то с натяжкой). ... Ну и плюс сам факт использования макросов. Так чем же это лучше? AD>Вот именно что привычен. Такой код будет проще поддерживать сиплюплюсникам старой закалки
Макросы всегда труднее поддерживать, а BOOST_PP_ENUM_PARAMS ещё и время компиляции немилосердно увеличивают.
Здравствуйте, B0FEE664, Вы писали:
BFE>Макросы всегда труднее поддерживать,
Это спорный вопрос. Например, чтобы понять смысл Param<I>... мне пришлось напрячься + я не сразу въехал зачем нужен template <size_t> using Param = Arg, несмотря на то, что я стараюсь держать себя в курсе фишек новых плюсов.
Здравствуйте, ArtDenis, Вы писали:
AD>Это спорный вопрос. Например, чтобы понять смысл Param<I>... мне пришлось напрячься + я не сразу въехал зачем нужен template <size_t> using Param = Arg, несмотря на то, что я стараюсь держать себя в курсе фишек новых плюсов.
Я специально акцентировал внимание, что это решение "навскидку", то есть эскиз, далекий от совершентсва. И даже при этом обе обозначенные проблемы решаются легким движением руки, если вынести это все в отдельную утилиту, как я предлагал здесь