我想从返回引用的方法中捕获异常,而不从后来使用引用的调用中捕获相同的异常。例如:
try {
Something &o = myMap.at(myIndex);
foo(o);
} catch(std::out_of_range &e) {
// If this was thrown by myMap.at, we can handle it
// If this was thrown by foo, we can't, and need to propagate it
}
所以我想做这样的事情:
Something &o;
try {
o = myMap.at(myIndex);
} catch(std::out_of_range &e) {
// Handle the error
}
foo(o);
但当然,那是无效的。我可以想办法将foo
的异常包装在另一个异常中,然后将其展开到try
之外,但这样做比较混乱。还有更好的方法吗?
可在此处找到MCVE:https://ideone.com/DJHxpO
答案 0 :(得分:6)
您可以使用立即调用的lambda表达式:
Something &o = [&]() -> decltype(auto) {
try {
return myMap.at(myIndex);
} catch(std::out_of_range &e) {
// Handle the error
// Return some other object for o to refer to.
}
}();
foo(o);
答案 1 :(得分:1)
您可以改为使用指针:
Something *o; // initialize it with nullptr if necessary
try {
o = &myMap.at(myIndex);
} catch(std::out_of_range &e) {
// Handle the error
}
foo(*o); // check whether it's nullptr before dereference if necessary
答案 2 :(得分:1)
一种适用于所有C ++版本的简单方法是
bool mapped = false;
try {
Something &o = myMap.at(myIndex);
mapped = true;
foo(o);
} catch(std::out_of_range &e) {
if (mapped) throw;
// if we get to here, the exception was thrown by myMap.at()
}
如果myMap.at()
失败,这也避免了引用引用其他对象的需要。
答案 3 :(得分:0)
我认为这是boost::optional
(std :: in c ++ 17)的一个很好的用例。
您并非真的想要生成或处理和例外,因为不在地图中的项目不是特殊情况。
我想我会这样表达:
int myIndex = 1;
foo(maybe_at(myMap, myIndex).value_or_eval([]()->Something& {
// perform error code here
return default_something;
}));
此处的完整代码示例:
#include <map>
#include <type_traits>
#include <boost/optional.hpp>
template<class Container>
struct container_traits
{
using maybe_const_type = std::remove_reference_t<Container>;
using container_type = std::decay_t<Container>;
using is_const = std::is_const<maybe_const_type>;
using key_type = typename container_type::key_type;
using raw_mapped_type = typename container_type::mapped_type;
using mapped_type = std::conditional_t<is_const::value, std::add_const_t<raw_mapped_type>, raw_mapped_type>;
using mapped_reference = std::add_lvalue_reference_t<mapped_type >;
};
template<class Container, class Key>
auto maybe_at(Container&& container, Key&& key)
{
using traits = container_traits<Container>;
using result_type = boost::optional<typename traits::mapped_reference>;
auto result = result_type {};
auto ifind = container.find(key);
if (ifind != container.end()) {
result = ifind->second;
}
return result;
}
struct Something {};
void foo(Something&) {}
void foo(const Something&) {}
std::map<int, Something> myMap1;
const std::map<int, Something> myMap2;
auto default_something = Something{};
int main() {
int myIndex = 1;
foo(maybe_at(myMap1, myIndex).value_or_eval([]()->Something& {
// perform error code here
return default_something;
}));
foo(maybe_at(myMap2, myIndex).value_or_eval([]()->Something const& {
// perform error code here
return default_something;
}));
}