5

関数オブジェクトへのポインタを指定すると、次のようになります。

std::shared_ptr<std::function<double(double)>> f;

std::bindステートメントでこのポインターを使用できるようにするC++11の組み込み構造はありますか?例えば:

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);

前もって感謝します。

編集:私はもっと明確にすべきだった。最適化のために、共有ポインター内の関数オブジェクトのインスタンスを使用する必要があります。

4

2 に答える 2

4

間接参照演算子の標準関数オブジェクトがある場合(withstd::plus<T>を追加する場合と同様)、ネストされたバインド式を含めることができますが、そうではありません。さらに、通常の置換を行うため、呼び出し演算子が必要になります。ネストされたバインド式の評価中の配置は、最初の引数には適用されません!あなたのソリューションは追加を導入するので、私はそうでないいくつかの代替案を提案しています。TTstd::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)...パラメータを置くことを少しお勧めします。これは、移動専用タイプを扱う場合に役立つことがあります。

于 2012-10-25T21:11:30.107 に答える
3

ここで使用できるちょっとしたハックがあります。これは、メンバー関数へのポインターで、ポインターまたは(さらに)スマートポインター(20.8.2p1の2番目の箇条書き、の定義)INVOKE が渡されると、オブジェクト引数を自動的に間接化することです。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);
于 2012-10-25T22:15:09.697 に答える