9

ファンクターを引数として取り、ファンクターを呼び出してから、その戻り値を にラップして返す関数を作成しようとしていますboost::shared_ptr

以下はコンパイルを拒否し、私はすべてアイデアがありません。「std::vector< std::string > は呼び出し演算子を提供していません」と表示されます (大まかに)。Mac OS X で Clang 3.1 を使用しています。

template< typename T >
boost::shared_ptr< T > ReturnValueAsShared(
    boost::function< T() > func )
{
  return boost::make_shared< T >( func() );
}

これは私がそれを使用しようとしているコンテキストです:

make_shared< packaged_task< boost::shared_ptr< std::vector< std::string > > > >(
   bind( ReturnValueAsShared< std::vector< std::string > >,
      bind( [a function that returns a std::vector< std::string >] ) ) );

編集: これは完全な自己完結型のテスト ケースです。このコードは同じエラーでコンパイルに失敗し、私の人生では何が問題なのかわかりません:

#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <string>
#include <vector>

std::vector< std::string > foo( std::string a )
{
  std::vector< std::string > vec;
  vec.push_back( a );
  return vec;
}

template< typename T >
boost::shared_ptr< T > ReturnValueAsShared(
    boost::function< T() > func )
{
  return boost::make_shared< T >( func() );
}

int main()
{
  auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
                        boost::bind( foo, std::string("a") ) );
  f();

} // main

エラー出力は次のとおりです。

In file included from testcase.cpp:3:
In file included from /usr/local/include/boost/function.hpp:64:
In file included from /usr/local/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:47:
In file included from /usr/local/include/boost/function/detail/function_iterate.hpp:14:
In file included from /usr/local/include/boost/function/detail/maybe_include.hpp:13:
/usr/local/include/boost/function/function_template.hpp:132:18: error: type 'std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >' does not provide a call operator
          return (*f)(BOOST_FUNCTION_ARGS);
                 ^~~~
/usr/local/include/boost/function/function_template.hpp:907:53: note: in instantiation of member function 'boost::detail::function::function_obj_invoker0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >::invoke' requested here
        { { &manager_type::manage }, &invoker_type::invoke };
                                                    ^
/usr/local/include/boost/function/function_template.hpp:722:13: note: in instantiation of function template specialization 'boost::function0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >::assign_to<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >' requested here
      this->assign_to(f);
            ^
/usr/local/include/boost/function/function_template.hpp:1042:5: note: in instantiation of function template specialization 'boost::function0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >::function0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >' requested here
    base_type(f)
    ^
/usr/local/include/boost/bind/bind.hpp:243:43: note: in instantiation of function template specialization 'boost::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > ()>::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >' requested here
        return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_]);
                                          ^
/usr/local/include/boost/bind/bind_template.hpp:20:27: note: in instantiation of function template specialization 'boost::_bi::list1<boost::_bi::bind_t<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > (*)(std::basic_string<char>), boost::_bi::list1<boost::_bi::value<std::basic_string<char> > > > >::operator()<boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >, boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > (*)(boost::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > ()>), boost::_bi::list0>' requested here
        BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
                          ^
testcase.cpp:27:4: note: in instantiation of member function 'boost::_bi::bind_t<boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >, boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > (*)(boost::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > ()>), boost::_bi::list1<boost::_bi::bind_t<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > (*)(std::basic_string<char>), boost::_bi::list1<boost::_bi::value<std::basic_string<char> > > > > >::operator()' requested here
  f();
   ^
1 error generated.

ここにいくつかの手がかりがあります。次のコードは問題なくコンパイルされますが、これは私が必要とするコードではないため、役に立ちません:)

#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <string>
#include <vector>

std::vector< std::string > foo()
{
  std::vector< std::string > vec;
  return vec;
}

template< typename T >
boost::shared_ptr< T > ReturnValueAsShared(
    boost::function< T() > func )
{
  return boost::make_shared< T >( func() );
}

int main()
{
  auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
                        foo );
  f();

} // main
4

3 に答える 3

3

boost::protect は行く方法です:

int main()
{
  auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
                        boost::protect(boost::bind( foo, std::string("a") ) ) );
  f();

} // main

これは可能な限りきれいです。

于 2012-07-16T08:53:47.150 に答える
2

一部の構造 ( などbind) は、実際にはノーズでキャプチャしたくない中間の「式」タイプを返します。その場合、 を介して型をキャプチャしてはならず、auto明示的な変換を指定する必要がある場合があります。そうしないと、一意の単一のユーザー定義の変換チェーンが存在しないためです。あなたの場合、バインド式から次への明示的な変換を追加しますfunction

typedef std::vector<std::string> G;
auto f = boost::bind(ReturnValueAsShared<G>,
             static_cast<boost::function<G()>(boost::bind(foo, std::string("a")))
                    );

(これ自体は実際には機能しませんが、対応するstd構造を使用すると機能します。)

于 2012-07-15T22:53:44.860 に答える
2

完全な書き直し、元の回答は正しくありませんでした。

エラー分析

ここで何が問題なのか最初はわからなかったので、いくつかの分析を行いました。今後の参照用に保管しています。問題を回避する方法については、以下の解決策を参照してください。

bind.hppこれを行います:

return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_]);

私の意見では、これは次のように翻訳されます。

unwrapper<F>::unwrap(f, 0) = ReturnValueAsShared< std::vector< std::string > >
base_type::a1_ = boost::bind( foo, std::string("a") )

したがって、このコードで期待されることは、関数に引数をそのまま渡すことです。しかし、これが機能するためには、式a[base_type::a1_]は型boots:_bi::value<T>である必要がありますが、ラップされていない型boost::_bi::bind_tです。そのため、ファンクターが引数として渡される代わりに、オーバーロードされた特別なバージョンが呼び出されます。

namespace boost { namespace _bi { class list0 {
    …
    template<class R, class F, class L>
    typename result_traits<R, F>::type
    operator[] (bind_t<R, F, L> & b) const {
        return b.eval(*this);
    }
    …
} } }

これは、nullary 関数を渡す代わりに評価します。そのため、ベクトルを返すオブジェクトの代わりに、引数はベクトルになりました。以降のステップでは、それを に変換しようとしてboost::function失敗します。

正準解

もう一度編集:ネストされたバインド
のこの特別な処理は、機能として意図されているようです。ユーザーの Zao さんと heller さんと話していると、これらの効果に対抗する機能があることがわかりました。したがって、この問題の標準的な解決策は次のようになります。#boostprotect

…
#include <boost/bind/protect.hpp>
…
  auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
    boost::protect ( boost::bind( foo, std::string("a") ) ) );
…
于 2012-07-15T20:42:40.603 に答える