从模板中绑定模板函数

时间:2010-12-19 17:55:11

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

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<RetType>, ...)。问题是为什么这是一个问题?更重要的是如何解决这个问题?

1 个答案:

答案 0 :(得分:4)

这绝对是惊人的,但取而代之的是:

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

by:

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

按预期运行(这实际上是您通过将bind移出registerFunc而执行的操作)。我试图理解它,但在那之前,这似乎是你的问题的解决方法,