Как обернуть функцию с различным числом аргументов по умолчанию, чтобы иметь только один аргумент?
У меня есть функция шаблона, назовите ее "клиентом":
template<typename T>
void client(T (*func)(const std::string&), const std::string& s) {}
Тогда существует ряд "адаптированных" функций, которые имеют одинаковый тип первого аргумента, отличного от значения по умолчанию, но следующие аргументы различаются по числу и имеют значения по умолчанию:
void adaptee_one(const std::string&, int i = 1, char* c = nullptr) {}
void adaptee_two(const std::string&, float* f = nullptr) {}
Вышеуказанные функции являются заданными. Теперь то, что я хочу сделать, - передать их вышеприведенной функции client<>()
в качестве первого параметра, и мне остается только передать первый аргумент, const std::string&
. Поэтому я делаю следующее:
void bindAdapteeOne(const std::string& s) {
return adaptee_one(s);
}
void bindAdapteeTwo(const std::string& s) {
return adaptee_two(s);
}
И затем перейдите bindAdapteeX()
в client<>()
.
То, что я хотел бы сделать, - автоматизировать упаковку или иметь одну (шаблонизированную) упаковку вместо одного адаптера. Я чувствую, что это может иметь место для вариаторов, но у них мало идеи о том, как их применять.
С++ 11 в порядке, С++ 14 прекрасно, если это абсолютно необходимо.
Ответы
Ответ 1
С++ 11 в порядке, С++ 14 прекрасно, если это абсолютно необходимо.
С++ 11 здесь.
То, что я хотел бы сделать, - автоматизировать обертывание или иметь одну (шаблонизированную) оболочку вместо одного адаптера.
Я бы этого не сделал. Вы можете просто использовать не захватывающие лямбды и позволить им распадаться на указатели функций:
client (+[](const std::string& s) { return adaptee_one(s); }, "foo");
Я не думаю, что обертывание их в материал шаблонов или что-то еще даст вам более читабельное или простое в использовании решение.
Как минимальный рабочий пример:
#include<string>
template<typename T>
void client(T (*func)(const std::string&), const std::string& s) {}
void adaptee_one(const std::string&, int i = 1, char* c = nullptr) {}
void adaptee_two(const std::string&, float* f = nullptr) {}
int main() {
client (+[](const std::string& s) { return adaptee_one(s); }, "foo");
}
Ответ 2
Это один из тех случаев, когда макрос помогает:
#define WRAP_FN(f) +[](std::string const& s) -> decltype(auto) { return f(s); }
Хотя вы могли бы просто написать тело этого встроенного текста.
Нет ничего другого, что вы могли бы сделать. Проблема в том, что аргументы по умолчанию не видны в сигнатуре функции, поэтому, как только вы попадаете в систему типов, нет возможности различать:
void works(std::string const&, int=0);
void fails(std::string const&, int );
Оба из них void(*)(std::string const&, int)
. Таким образом, у вас не может быть шаблона функции или оболочки шаблона шаблона - вам нужно сделать это с помощью lambda (или макроса, который обертывает лямбда).
Ответ 3
Я думаю, что создам класс, который обертывает ваши параметры, и клиент примет экземпляр этого класса. Таким образом, у вас есть только один параметр, который содержит сколько угодно параметров.
Эта оболочка параметров также предоставит значения по умолчанию и позволит вам уточнить их в производных классах для определенных целей.
Это, вероятно, немного больше самодокументируется, когда по сравнению с лямбдами.
И кто знает, когда его время читать и записывать параметры из файла, класс оболочки был бы идеальным местом для этого.