从模板内绑定模板函数

发布于 2024-10-08 08:04:04 字数 4086 浏览 1 评论 0原文

延续这个问题。我正在尝试绑定一个返回 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, ...) 。问题是为什么这是一个问题?更重要的是如何解决这个问题?

In a continuation from this question. I'm trying to bind a given function that returns something-other-than void to be able to simply call f() later. However the following code fails to compile on GCC 4.4. It compiles on VS 2010, but the resulting program crashes.

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 produces this crazy message:

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 = ]’

I don't have enough knowledge of the inner STL workings to make anything out of that.

However while experimenting I found out that if I remove the second std::bind call from the registerFunc template like this:

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

The code works as expected both in VS and GCC. So my conclusion is that the problem is in calling std::bind(_hideRet<RetType>, ...) from within a template function. The question is why is that a problem? And more importantly how to fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

香橙ぽ 2024-10-15 08:04:04

这绝对是令人惊奇的,但是在 Visual Studio 2010 下将 : 替换

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

会按预期运行(这本质上就是将第二个 bind 移出 registerFunc 所做的事情)。我试图理解它,但在那之前,这似乎是解决你的问题的方法,

This is absolutely amazing, but replacing :

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

under Visual Studio 2010 runs as expected (which is essentially what you did by moving the second bind out of registerFunc). I'm trying to make sense out of it, but until then, that seems like a workaround for your issue,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文