【问题标题】:Binding a template function from within a template从模板中绑定模板函数
【发布时间】:2010-12-20 02:28:37
【问题描述】:

继续this question。我正在尝试绑定一个给定的函数,该函数返回除了 void 之外的东西,以便以后能够简单地调用 f() 。但是,以下代码无法在 GCC 4.4 上编译。它在 VS 2010 上编译,但结果程序崩溃。

template<typename RetType>
void _hideRet(std::function<RetType ()> func, RetType * ret)
{
    *ret = func();
}

template<typename FuncType, typename RetType, typename ParamType>
std::function<void ()> registerFunc(FuncType func, RetType * ret, ParamType param)
{
    auto f = std::bind(func, std::forward<ParamType>(param));
    return std::bind(_hideRet<RetType>, f, ret);
}

int myFunction(std::string text)
{
    std::cout << text << std::endl;
    return 42;
}

int main()
{
    int ret = 0;
    auto f = registerFunc(myFunction, &ret, "text");
    f();
    std::cout << ret << std::endl;
    return 0;
}

GCC 产生了这个疯狂的信息:

In file included from /usr/include/c++/4.4/functional:70,
                 from func.cpp:4:
/usr/include/c++/4.4/tr1_impl/functional: In member function ‘typename std::result_of<_Functor(typename std::result_of<std::_Mu<_Bound_args, std::is_bind_expression::value, (std::is_placeholder::value > 0)>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::__call(const std::tuple<_UElements ...>&, std::_Index_tuple<_Indexes ...>) [with _Args = , int ..._Indexes = 0, 1, _Functor = void (*)(std::function<int()>, int*), _Bound_args = std::_Bind<int (*(const char*))(std::string)>, int*]’:
/usr/include/c++/4.4/tr1_impl/functional:1191:   instantiated from ‘typename std::result_of<_Functor(typename std::result_of<std::_Mu<_Bound_args, std::is_bind_expression::value, (std::is_placeholder::value > 0)>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) [with _Args = , _Functor = void (*)(std::function<int()>, int*), _Bound_args = std::_Bind<int (*(const char*))(std::string)>, int*]’
/usr/include/c++/4.4/tr1_impl/functional:1668:   instantiated from ‘static void std::_Function_handler<void(_ArgTypes ...), _Functor>::_M_invoke(const std::_Any_data&, _ArgTypes ...) [with _Functor = std::_Bind<void (*(std::_Bind<int (*(const char*))(std::string)>, int*))(std::function<int()>, int*)>, _ArgTypes = ]’
/usr/include/c++/4.4/tr1_impl/functional:2005:   instantiated from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor, typename __gnu_cxx::__enable_if<(! std::is_integral::value), std::function<_Res(_ArgTypes ...)>::_Useless>::__type) [with _Functor = std::_Bind<void (*(std::_Bind<int (*(const char*))(std::string)>, int*))(std::function<int()>, int*)>, _Res = void, _ArgTypes = ]’
func.cpp:16:   instantiated from ‘std::function<void()> registerFunc(FuncType, RetType*, ParamType) [with FuncType = int (*)(std::string), RetType = int, ParamType = const char*]’
func.cpp:28:   instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid conversion from ‘int’ to ‘std::_M_clear_type*’
/usr/include/c++/4.4/tr1_impl/functional:1137: error:   initializing argument 1 of ‘std::function<_Res(_ArgTypes ...)>::function(std::_M_clear_type*) [with _Res = int, _ArgTypes = ]’

我对内部 STL 工作原理没有足够的了解,无法从中做出任何事情。

但是,在试验过程中,我发现如果我从 registerFunc 模板中删除第二个 std::bind 调用,如下所示:

template<typename FuncType, typename RetType, typename ParamType>
std::function<RetType ()> registerFunc(FuncType func, RetType *, ParamType param)
{
    return std::bind(func, std::forward<ParamType>(param));
}

// in main
auto tmp = registerFunc(myFunction, &ret, "text");
auto f = std::bind(_hideRet<int>, tmp, &ret);
f();

代码在 VS 和 GCC 中都按预期工作。所以我的结论是问题在于从模板函数中调用std::bind(_hideRet&lt;RetType&gt;, ...)。问题是为什么这是一个问题?更重要的是如何解决这个问题?

【问题讨论】:

    标签: c++ templates c++11 bind


    【解决方案1】:

    这绝对是惊人的,但要替换:

    auto f = std::bind(func, std::forward<ParamType>(param));
    return std::bind(_hideRet<RetType>, f, ret);
    

    作者:

    std::function<RetType ()> f = std::bind(func, std::forward<ParamType>(param));
    return std::bind(_hideRet<RetType>, f, ret);
    

    在 Visual Studio 2010 下按预期运行(这实际上是您将第二个 bind 移出 registerFunc 所做的)。我正在尝试理解它,但在那之前,这似乎是解决您的问题的一种解决方法,

    【讨论】:

    • @Fiktik:我希望我能理解为什么 :) 从我的角度来看,您的原始代码应该可以工作
    • ParamType 可能是错误的并被实例化为const char*,而正确的ParamType 将是std::string
    • 甚至可以是:return std::bind(_hideRet&lt;RetType&gt;, std::function&lt;RetType ()&gt;(std::bind(func, std::forward&lt;ParamType&gt;(param))), ret);
    • @smerlin ParamType 当然实例化为const char *,我指望它并要求它以这种方式工作。这也是我为 FuncType 使用模板类型而不是 std::function&lt;RetType (ParamType)&gt; 的原因 - 因为它会产生不必要的限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 2016-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多