使用boost :: optional捕获和包装异常

时间:2016-10-18 01:18:31

标签: c++ boost c++14 optional boost-optional

我希望捕获库代码生成的异常,并将它们包装在boost::optional s(或std::experimental::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;
}

当试图编译&#34;破坏&#34;例如,我得到以下输出:

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)...))>>
     ^

我能够通过创建具有正确类型的函数指针来解决问题,但这并不理想。有没有解决我的问题的方法,还是我坚持使用丑陋的函数指针hack?

干杯, 莱恩

1 个答案:

答案 0 :(得分:2)

在第一种情况下,您可能希望传递两种不同版本的func1。编译器无法弄清楚实例化模板所需的func1类型,因此它没有达到“查看内部”模板的程度,看看“一个参数”版本是正确的。

这就是编译器错误消息告诉你的内容。

在第二种情况下,您选择func1的一个重载并将其传递给try_call。没有歧义,因此编译器可以确定要应用于模板的签名。