Дан указатель на объект функции:
std::shared_ptr<std::function<double(double)>> f;
есть ли встроенная конструкция в C ++ 11, которая позволяет использовать этот указатель в std::bind
заявление? Например:
std::function<double()> g = std::bind(built_in(f), 0.0);
Что я делаю, так это использую вариационный шаблон как:
template<typename Ret, typename... Args>
std::function<Ret(Args...)> get_fn(const std::shared_ptr<std::function<Ret(Args...)>>& f)
{
return [=](Args... args) -> Ret { return (*f)(args...); };
}
Это позволяет мне написать:
std::function<double()> g = std::bind(get_fn(f), 0.0);
Заранее спасибо.
Редактировать: Я должен был быть более ясным. Мне нужно использовать экземпляр объекта функции внутри общего указателя в целях оптимизации.
Если бы у нас был стандартный объект функции для оператора разыменования (очень похоже на std::plus<T>
для добавления T
с T
) тогда мы могли бы задействовать вложенное выражение связывания, но это не так — плюс нам понадобится оператор вызова, потому что обычные замены, которые имеют место во время вычисления вложенных выражений связывания, не применяются к первому аргументу! Ваше решение вводит дополнительный std::function
Поэтому я предлагаю несколько альтернатив, которые этого не делают.
Напишите свой собственный оператор вызова и разыменования:
struct call {
template<typename Callable, typename... Args>
auto operator()(Callable&& callable, Args&&... args) const
// don't use std::result_of
-> decltype( std::declval<Callable>()(std::declval<Args>()...) )
{ return std::forward<Callable>(callable)(std::forward<Args>(args)...); }
};
struct dereference {
template<typename T>
auto operator()(T&& t) const
-> decltype( *std::declval<T>() )
{ return *std::forward<T>(t); }
};
template<typename IndirectCallable, typename... Args>
auto indirect_bind(IndirectCallable&& f, Args&&... args)
-> decltype( std::bind(call {}
, std::bind(dereference {}, std::declval<IndirectCallable>())
, std::declval<Args>()... ) )
{ return std::bind(call {}
, std::bind(dereference {}, std::forward<IndirectCallable>(f))
, std::forward<Args>()... ); }
Вы можете тогда сделать auto g = indirect_bind(f, 0.0);
, Вот подтверждение концепции это также показывает, как заполнители должным образом обрабатываются.
Я упоминаю вышеупомянутое решение, потому что функторы как call
а также dereference
полезные кирпичи — я лично их среди своих инструментов. Мое предпочтительное решение, однако, было бы написать полиморфный функтор, который выполняет перенаправление и вызов за один раз:
template<typename Indirect>
struct indirect_callable_type {
// Encapsulation left as an exercise
Indirect f;
template<typename... Args>
auto operator()(Args&&... args)
// don't use std::result_of
-> decltype( std::declval<Indirect&>()(std::declval<Args>()...) )
{ return f(std::forward<Args>(args)...); }
template<typename... Args>
auto operator()(Args&&... args) const
// don't use std::result_of
-> decltype( std::declval<Indirect const&>()(std::declval<Args>()...) )
{ return f(std::forward<Args>(args)...); }
// Lvalue and rvalue *this version also left as an exercise
};
template<typename T>
indirect_callable_type<typename std::decay<T>::type>
make_indirect_callable(T&& t)
{ return { std::forward<T>(t) }; }
который вы можете использовать как auto g = std::bind(make_indirect_callable(f), 0.0);
,
Я должен отметить, что, в отличие от вашего решения, для этого необходимо написать некоторые типы вне строки. Это печальная ситуация из-за ограничений, присущих лямбда-выражениям. Если вы хотите придерживаться того, что у вас есть в настоящее время, у меня есть небольшая рекомендация: std::forward<Args>(args)...
параметры. Это может оказаться полезным, если вы когда-либо имеете дело с типами только для перемещения.
Здесь вы можете использовать хороший маленький взлом, который заключается в том, что INVOKE
по указателю на функцию-член автоматически перенаправляет свой аргумент объекта, когда передается указатель или (даже) умный указатель (20.8.2p1 вторая точка, определение INVOKE
):
#include <functional>
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<std::function<double(double)>> f
= std::make_shared<std::function<double(double)>>(
[](double d) { return d + 10.0; });
std::function<double()> g = std::bind(
&std::function<double(double)>::operator(), f, 0.0);
std::cout << g() << std::endl;
}
Если вы не хотите явно указывать тип f
:
std::function<double()> g = std::bind(
&std::remove_reference<decltype(*f)>::type::operator(), f, 0.0);