Мне нужна функция bind
, которая ведет себя как std::bind
, но возвращает соответствующую специализацию std::function
.std :: bind-like функция возвращает std :: function
Я думаю, что аргументы шаблона std::function
можно извлечь, используя номер заполнителя из параметра функции. Однако это не выглядит тривиальным. Существует ли какая-либо реализация?
Почему мне это нужно
Я хочу реализовать waterfall
функции с семантикой, похожей на this JavaScript one.
Вот как я себе это будет выглядеть в C++:
std::function<void(const std::string &)> f = waterfall(
[](const std::function<void(int)> &cb, const std::string &) {
...;
cb(1);
},
[](const std::function<void(double, double)> &cb, int) {
...;
cb(0.5, 10);
},
[](double, double) {
}
);
Другими словами, waterfall
бы кучу функций, каждая из которых (кроме последнего) принимает функцию в качестве первого параметр. waterfall
свяжет каждую функцию с предыдущей (начиная с последней, конечно) и возвращает одну функцию.
В основном водопад должен быть чем-то вроде этого:
// recursion termination: `waterfall` called with a single functions
template< typename Arg >
auto waterfall(const Arg& first) -> decltype(first) {
return first;
}
// recursion: `waterfall` called with mulitple functions
template< typename Arg, typename... Args >
... waterfall(const Arg& first, Args... args) {
return std::bind(first, waterfall(std::forward<Args>(args)...));
}
Есть три открытые проблемы, хотя:
- выясняя тип возвращаемого
waterfall
при вызове с несколькими аргументами. Это не может бытьdecltype(std::bind(first, waterfall(...)))
(потому что C++ не позволяет рекурсивно вызывать функцию шаблона, чтобы вывести его тип). Если бы я знал тип функции (т. Е.Arg
), то без первого аргумента был бы тип возвращаемого типа, который я ищу. - Я думаю, мне нужно знать количество аргументов
first
, чтобы правильноstd::bind
. std::bind
тип возврата не ведет себя так, как я хочу: вложенныеstd::bind
звонки объединяет все связанные функции вместе, а не составлять их.
я смог обойти третью точку, написав std::bind
оболочку, которая обертывает связанную функцию в объект типа T
таким образом, что std::is_bind_expression<T>::value == false
.
Для первых двух точек мне нужно выяснить тип возвращаемого значения и аргументы типа waterfall
. Это было бы тривиально, если бы функции были std::function
с. Было бы также просто, если бы они были лямбдами, классическими функциями или функторами с одним operator()
: мне просто нужно было использовать что-то вроде this function_traits
. Однако я бы действительно бы передать функции, связанные с использованием std::bind
к waterfall
, без необходимости вручную ввергнут их в std::function
с, потому что это делает мой код путь короче и пути яснее с большими waterfall
с.
Любые идеи, мысли или предложения?
В C++ 11 вам следует предпочесть использовать лямбда-выражения над 'std :: bind' и друзьями. Можете ли вы показать пример того, что вы хотите сделать? Обратите внимание, что блокировки лямбда неявно конвертируются в 'std :: function's. – 5gon12eder
Можете ли вы объяснить, как вы собираетесь использовать это? И почему вы думаете, что вам это нужно? В общем случае вы не можете вывести уникальную подпись для объекта вызова функции, не говоря уже о том, что имеет некоторые аргументы. Почти всегда потребитель объекта знает, как он будет называть объект, и как таковой должен быть тот, который определяет тип стирания, а не поставщик вызываемого объекта. Наиболее распространенной недостоверной причиной является то, что вы пишете протокол удаленного вызова (из другого пространства памяти или другого языка), и даже там интерфейс протокола должен определять подпись! – Yakk
Существует один ответ здесь http://stackoverflow.com/a/21788988/683218 (by dyp) на мой вопрос о том, как вернуть объект типа связывания, который не позволяет лишние параметры. Я не знаю, является ли это актуальным или вы можете адаптировать его для возврата объекта std :: function. – tinlyx