【问题标题】:"<class name> does not provide a call operator" error when trying to wrap function return value尝试包装函数返回值时出现“<class name> 不提供调用运算符”错误
【发布时间】:2012-07-14 17:40:38
【问题描述】:

我正在尝试编写一个函数,该函数将函子作为参数,调用函子,然后返回包裹在boost::shared_ptr 中的返回值。

以下内容拒绝编译,我完全没有想法。我得到“std::vector 不提供呼叫运算符”(大致)。我在 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

【问题讨论】:

  • 请简化问题并提供最小(非)工作示例代码。
  • @KerrekSB 当我尝试将其用作ReturnValueAsShared&lt; std::vector&lt; std::string &gt; &gt; 时,错误为std::vector&lt;std::string&gt; does not provide a call operator
  • @KonradRudolph 我会尽量减少它。
  • @KonradRudolph 添加了测试用例。
  • 嗯,看起来 Boost 不是那么好。只要您在 bind 调用周围添加对 std::function&lt;std::vector&lt;std::string&gt;&gt;()&gt; 的显式转换,std 版本就可以工作。

标签: c++ templates boost boost-function


【解决方案1】:

boost::protect 是要走的路:

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

} // main

这是尽可能干净的。

【讨论】:

  • 可以通过解释 boost::protect 是什么、它的作用以及更详细描述它的文档的链接来改进这个答案。
【解决方案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 结构,它确实有效。)

【讨论】:

  • 用演员 boost::function&lt; std::vector&lt; std::string &gt;() &gt;(...) 包裹我的第二个 bind 电话使一切正常。感谢您的信息。
【解决方案3】:

完全重写,原答案不正确。

错误分析

因为一开始我不知道这里出了什么问题,所以我做了一些分析。我保留它以供将来参考;请参阅下面的解决方案,了解如何避免该问题。

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&lt;T&gt; 类型,而它是未包装类型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);
    }
    …
} } }

这将评估空函数,而不是传递它。因此,现在的参数不是返回向量的对象,而是向量。后续步骤将尝试将其转换为 boost::function 并失败。

规范解决方案

再次编辑:
看起来这种对nested binds 的特殊处理旨在作为一项功能。与用户 Zao 和 heller 讨论 #boost,我现在知道有一个 protect 函数可以对抗这些影响。所以这个问题的典型解决方案似乎如下:

…
#include <boost/bind/protect.hpp>
…
  auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
    boost::protect ( boost::bind( foo, std::string("a") ) ) );
…

【讨论】:

  • 不,返回值是一个仿函数,执行时返回一个shared_ptr。如果我用(*f)() 替换f(),我会得到一个编译器错误,抱怨f 不是指针类型。
  • 好的,你说得对,问题更深一层。在我看来bindshared_ptr 没有重载,因此默认情况下它假定一个函数对象。但是由于shared_ptr 没有提供呼叫操作员,所以事情失败了。
  • 嗯,bind 不需要为shared_ptr 重载,它是一个模板。此外,错误抱怨vector&lt;string&gt; 没有呼叫操作员,而不是shared_ptr
  • 对于您编辑的版本:您似乎缺少auto f = ... 中的ReturnValueAsShared 前面有一个boost::bind(。代码绝不会尝试调用shared_ptr&lt;...&gt;::operator()
  • 好的,关于vector&lt;string&gt; 是一个好点。我将暂时留下我的答案,作为失败努力的文档,但一旦找到正确的答案,我希望最终将其删除。
猜你喜欢
  • 2020-04-10
  • 2021-09-13
  • 1970-01-01
  • 2021-02-20
  • 2019-12-02
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多