2016-10-18 6 views
1

ライブラリコードで生成された例外をキャッチしてboost::optional(またはstd::experimental::optional)にラップしたいと思います。私のコードは簡単なケースでは機能しますが、オーバーロードされた関数を呼び出すときに正しい型を推測するのは難しいです。私はこれに私のテストケースを低減しました:boost :: optionalで例外をキャッチしてラップする

// Compile with: clang++ -std=c++14 -stdlib=libc++ -Wall -Wshadow -Wextra -o except_to_optional except_to_optional.cpp 
#include <iostream> 
#include <boost/optional.hpp> 

template<typename Func, typename... Args> 
auto try_call(Func f, Args&&... args) noexcept -> boost::optional<std::decay_t<decltype(f(std::forward<Args>(args)...))>> 
{ 
    using RT = std::decay_t<decltype(f(std::forward<Args>(args)...))>; 
    try { 
    return boost::make_optional<RT>(f(std::forward<Args>(args)...)); 
    } catch(...) { 
    return boost::none; 
    } 
} 

int func1(char * ptr) 
{ 
    if (!ptr) 
    throw 14; 

    return strlen(ptr); 
} 

int func1(char * ptr, size_t len) 
{ 
    if (!ptr) 
    throw 14; 

    const size_t calc_len = strlen(ptr); 
    return calc_len < len ? calc_len : len; 
} 

int main(int argc, char **argv) 
{ 
    char *omg = "omg"; 

#if 1 
    // This is the desired syntax, but it fails 
    auto val = try_call(func1, omg); 
#else 
    // This works, but its ugly 
    int (*f)(char *) = func1; 
    auto val = try_call(f, omg); 
#endif 

    if (val) 
    std::cout << omg << " has a length of " << *val << "\n"; 
    else 
    std::cout << "Something went wrong...\n"; 

    return 0; 
} 

「壊れた」例をコンパイルしようと、私は次のような出力を得る:

except_to_optional.cpp:50:14: error: no matching function for call to 'try_call' 
    auto val = try_call(func1, omg); 
      ^~~~~~~~ 
except_to_optional.cpp:17:6: note: candidate template ignored: couldn't infer template argument 'Func' 
auto try_call(Func f, Args&&... args) noexcept -> boost::optional<std::decay_t<decltype(f(std::forward<Args>(args)...))>> 
    ^

私がすることができるよサイドステップの問題を正しい型の関数ポインタを作成することで、これは理想的ではありません。私の問題を解決する方法があるのですか?あるいは、醜い関数ポインタのハックに悩まされていますか?

乾杯、最初のケースで ライアン

+0

完璧な転送ラムダでオーバーロードされた関数名をラップします。 – Yakk

+0

Offtopic:提案されたBoost.Outcome(https://github.com/ned14/boost.outcome)の結果が、エラー状態を保存しながらTを返すためにオプションよりもずっとうれしいかもしれません。オプションと同じAPIを持っています。また、ほとんどの例外を同等の結果(std :: error_code)に変換することもできます。 –

答えて

2

、あなたが合格することをお勧めしますfunc1の2つの異なるバージョンがあります。 Theeコンパイラは、テンプレートをインスタンス化する必要があるタイプのfunc1を見つけることができないため、テンプレートを「見ている」というポイントには達しません。

これは、コンパイラのエラーメッセージがあなたに伝えていることです。

2番目のケースでは、func1の1つのオーバーロードを選択し、それをtry_callに渡しています。あいまいさがないので、コンパイラはテンプレートにどのような署名を適用するのか把握することができます。

+1

私は実際の問題は "*私の問題の解決策ですか?または醜い関数ポインタのハックに固執していますか?" * AFAIK Boost.Bindは、ユーザーからの曖昧さ回避が必要なように管理しています(関数ポインタのオーバーロード私が推測する他の呼び出し可能なコールバック?)。 – ildjarn

+0

私は自分の頭の上から解決策を見ませんが、それは夜遅くて、0500年以降起きているかもしれません。 –