Шаблон функции как аргумент шаблона
Я просто запутался, как реализовать что-то в общем виде на С++. Это немного запутанно, поэтому позвольте мне объяснить шаг за шагом.
Рассмотрим такой код:
void a(int) {
// do something
}
void b(int) {
// something else
}
void function1() {
a(123);
a(456);
}
void function2() {
b(123);
b(456);
}
void test() {
function1();
function2();
}
Легко заметить, что function1
и function2
делают то же самое, причем единственной другой частью является внутренняя функция.
Поэтому я хочу сделать function
generic, чтобы избежать избыточности кода. Я могу сделать это с помощью указателей функций или шаблонов. Позвольте мне выбрать последнее на данный момент. Мое мышление заключается в том, что это лучше, поскольку компилятор, несомненно, сможет встроить функции - я прав? Могут ли компиляторы по-прежнему встроить вызовы, если они сделаны с помощью указателей функций? Это побочный вопрос.
ОК, вернемся к исходной точке... Решение с шаблонами:
void a(int) {
// do something
}
void b(int) {
// something else
}
template<void (*param)(int) >
void function() {
param(123);
param(456);
}
void test() {
function<a>();
function<b>();
}
Все ОК. Но я столкнулся с проблемой: могу ли я это сделать, если a
и b
являются самими генериками?
template<typename T>
void a(T t) {
// do something
}
template<typename T>
void b(T t) {
// something else
}
template< ...param... > // ???
void function() {
param<SomeType>(someobj);
param<AnotherType>(someotherobj);
}
void test() {
function<a>();
function<b>();
}
Я знаю, что параметр шаблона может быть одним из следующих:
- тип,
- тип шаблона,
- значение типа.
Никто из них, похоже, не охватывает мою ситуацию. Мой главный вопрос: Как это решить, т.е. Определить function()
в последнем примере?
(Да, указатели на функции, похоже, являются обходным путем в этом конкретном случае - при условии, что они также могут быть встроены - но я ищу общее решение для этого класса проблем).
Ответы
Ответ 1
Чтобы решить эту проблему с помощью шаблонов, вы должны использовать параметр шаблона шаблона.
К сожалению, вы не можете передать шаблонную шаблонную функцию как тип, потому что ее нужно сначала создать. Но есть обходное решение с фиктивными структурами. Вот пример:
template <typename T>
struct a {
static void foo (T = T ())
{
}
};
template <typename T>
struct b {
static void foo (T = T ())
{
}
};
struct SomeObj {};
struct SomeOtherObj {};
template <template <typename P> class T>
void function ()
{
T<SomeObj>::foo ();
T<SomeOtherObj>::foo ();
}
int main ()
{
function<a>();
function<b>();
}
Ответ 2
Вот путь. Это может быть не самое лучшее, но оно работает:
template <typename T, T param>
void function() {
param(123);
param(456);
}
void test()
{
function< void(*)(int), a<int> >(); // space at end necessary to compiler
function< void(*)(int), b<int> >(); // because the C++ grammar is ambiguous
}
Независимо от того, будут ли они встраиваться, зависит от компилятора, но я был бы очень удивлен, если бы они не были.
EDIT: Хорошо, я немного ушел сегодня и пропустил ту часть, где параметры имеют разные типы. Мой плохой.
Может быть сложный способ сделать это с помощью шаблонов, но это самый простой способ, о котором я мог думать:
#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0)
Я знаю, я знаю, "макросы злы", бла-бла-бла. Оно работает. Если function
должен быть более сложным, чем ваш пример, вы можете столкнуться с проблемами, но это намного проще, чем все, что я смог придумать.
Ответ 3
template < typename F >
void function(F f)
{
f(123);
}
void a(int x) { ... }
struct b { void operator() (int x) { ... } };
void outer()
{
function(&a);
function(b());
}