2010-12-19 13 views
4

this questionの続き。私は後で単にf()を呼び出すことができるように、void以外の何かを返す関数をバインドしようとしています。しかし、次のコードはGCC 4.4でコンパイルできません。それはVS 2010でコンパイルされますが、結果として生じるプログラムがクラッシュします。私はそれの外に何かを作るために内部のSTLの仕組みの十分な知識を持っていないテンプレート内からのテンプレート関数のバインド

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

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は、このクレイジーなメッセージを生成します。しかし

私は私はこのような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>, ...)を呼び出すことにあるということです。問題はそれがなぜ問題なのか?さらに重要なことに、これを修正する方法は?

答えて

4

これは絶対に素晴らしいですが、交換:

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

あなたがregisterFuncのうち、二bindを移動することによって、何をしたか、本質的である(予想2010回の実行としてのVisual Studioの下で)。私はそれを理解しようとしていますが、それまではあなたの問題の回避策のように思えます。

+1

この回避策はGCCも満たしていることを確認できます。 – Fiktik

+0

@Fiktik:なぜ私は理解したかったのですか?オリジナルのコードは私の立場からはたらきます。 – icecrime

+0

ParamTypeは間違っていて、 'const char *'としてインスタンス化されますが、正しいParamTypeは 'std :: string'です。 – smerlin

関連する問題