I think I've almost figured out how to use an exception handling support from Boost Outcome with regards to the ErrorOr<T>
type from the LLVM support library.
I've defined an extension for the BOOST_OUTCOME_TRY
macro for the type llvm::ErrorOr<std::unique_ptr<T>>
. In a test application, this fails to compile, producing an error message that I honestly don't know how to interpret.
#include <llvm/Support/MemoryBuffer.h>
#include <boost/outcome.hpp>
namespace outcome = BOOST_OUTCOME_V2_NAMESPACE;
BOOST_OUTCOME_V2_NAMESPACE_BEGIN
template<class T>
inline bool try_operation_has_value(const llvm::ErrorOr<std::unique_ptr<T>>& v)
{
return static_cast<bool>(v);
}
template<class T>
inline auto try_return_as(const llvm::ErrorOr<std::unique_ptr<T>>& v)
{
if (!v) {
return failure(v->getError());
}
}
template<class T>
inline auto try_operation_extract_value(
const llvm::ErrorOr<std::unique_ptr<T>>& v)
{
return (*v).get();
}
BOOST_OUTCOME_V2_NAMESPACE_END
int test_stdin()
{
BOOST_OUTCOME_TRY(const auto& ibuff, llvm::MemoryBuffer::getSTDIN());
return 0;
}
This is for an application of llvm::MemoryBuffer
from the LLVM support library. The static method llvm::MemoryBuffer::getSTDIN())
is declared as having a return type ErrorOr<std::unique_ptr<MemoryBuffer>>
After I try to compile this code, the following two items appear under an error squiggly in VS Code, at my application of the BOOST_OUTCOME_TRY
macro.
no instance of overloaded function "boost::outcome_v2::try_operation_return_as" matches the argument listC/C++(304)
main.cpp(78, 3): argument types are: (llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer>>>)
Second item:
no matching function for call to 'try_operation_return_as'GCC
try.hpp(375, 32): expanded from macro 'BOOST_OUTCOME_TRY'
try.hpp(191, 35): expanded from macro 'BOOST_OUTCOME_TRY_CALL_OVERLOAD'
try.hpp(188, 55): expanded from macro 'BOOST_OUTCOME_TRY_OVERLOAD_MACRO'
try.hpp(375, 32): skipping 5 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all
try.hpp(316, 36): expanded from macro 'BOOST_OUTCOME_TRYA'
try.hpp(251, 3): expanded from macro 'BOOST_OUTCOME_TRY2_SUCCESS_LIKELY'
try.hpp(236, 21): expanded from macro 'BOOST_OUTCOME_TRYV2_SUCCESS_LIKELY'
try.hpp(129, 33): candidate template ignored: requirement 'detail::has_as_failure(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
try.hpp(138, 33): candidate template ignored: requirement 'detail::has_assume_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
try.hpp(147, 33): candidate template ignored: requirement 'detail::has_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
More detail, under the same error squiggly location in VS Code. (Maybe there's an explanation here?)
#define BOOST_OUTCOME_TRY(__VA_ARGS__...) BOOST_OUTCOME_TRY_CALL_OVERLOAD(BOOST_OUTCOME_TRY_INVOKE_TRY, __VA_ARGS__)
! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
Expands to:
auto _outcome_try_unique_name_temporary2 = (llvm::MemoryBuffer::getSTDIN()); if(::boost::outcome_v2::try_operation_has_value(_outcome_try_unique_name_temporary2)) [[likely]]; else { auto _outcome_try_unique_name_temporary2_f(::boost::outcome_v2::try_operation_return_as(static_cast<decltype(_outcome_try_unique_name_temporary2) &&>(_outcome_try_unique_name_temporary2))); return _outcome_try_unique_name_temporary2_f; }; const auto& ibuff = ::boost::outcome_v2::try_operation_extract_value(static_cast<decltype(_outcome_try_unique_name_temporary2) &&>(_outcome_try_unique_name_temporary2))
That seems to appear in the compiler output as follows:
[build] /projects/sandbox/cpp_sandbox_10/source/main.cpp:78:3: error: no matching function for call to 'try_operation_return_as'
[build] 78 | BOOST_OUTCOME_TRY(const auto& ibuff, llvm::MemoryBuffer::getSTDIN());
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:375:32: note: expanded from macro 'BOOST_OUTCOME_TRY'
[build] 375 | #define BOOST_OUTCOME_TRY(...) BOOST_OUTCOME_TRY_CALL_OVERLOAD(BOOST_OUTCOME_TRY_INVOKE_TRY, __VA_ARGS__)
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:191:35: note: expanded from macro 'BOOST_OUTCOME_TRY_CALL_OVERLOAD'
[build] 191 | BOOST_OUTCOME_TRY_OVERLOAD_GLUE(BOOST_OUTCOME_TRY_OVERLOAD_MACRO(name, BOOST_OUTCOME_TRY_COUNT_ARGS_MAX8(__VA_ARGS__)), (__VA_ARGS__))
[build] | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:188:55: note: expanded from macro 'BOOST_OUTCOME_TRY_OVERLOAD_MACRO'
[build] 188 | #define BOOST_OUTCOME_TRY_OVERLOAD_MACRO(name, count) BOOST_OUTCOME_TRY_OVERLOAD_MACRO1(name, count)
[build] | ^
[build] note: (skipping 5 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:316:36: note: expanded from macro 'BOOST_OUTCOME_TRYA'
[build] 316 | #define BOOST_OUTCOME_TRYA(v, ...) BOOST_OUTCOME_TRY2_SUCCESS_LIKELY(BOOST_OUTCOME_TRY_UNIQUE_NAME, return, v, __VA_ARGS__)
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:251:3: note: expanded from macro 'BOOST_OUTCOME_TRY2_SUCCESS_LIKELY'
[build] 251 | BOOST_OUTCOME_TRYV2_SUCCESS_LIKELY(unique, retstmt, var, __VA_ARGS__); \
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:236:21: note: expanded from macro 'BOOST_OUTCOME_TRYV2_SUCCESS_LIKELY'
[build] 236 | auto unique##_f(::BOOST_OUTCOME_V2_NAMESPACE::try_operation_return_as(static_cast<decltype(unique) &&>(unique))); \
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:129:33: note: candidate template ignored: requirement 'detail::has_as_failure(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
[build] 129 | constexpr inline decltype(auto) try_operation_return_as(T &&v, detail::as_failure_overload = {})
[build] | ^
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:138:33: note: candidate template ignored: requirement 'detail::has_assume_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
[build] 138 | constexpr inline decltype(auto) try_operation_return_as(T &&v, detail::assume_error_overload = {})
[build] | ^
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:147:33: note: candidate template ignored: requirement 'detail::has_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
[build] 147 | constexpr inline decltype(auto) try_operation_return_as(T &&v, detail::error_overload = {})
[build] | ^
I think this is centered on how the BOOST_OUTCOME_TRY
macro is being expanded here, using those three functions above as an extension for BOOST_OUTCOME_TRY
.
I wonder if anyone can help to clarify what's failing when that compiles?
I'm hoping that one could be able to reuse this albeit trivial extension onto the boost outcome support, when applying this and other static methods of llvm::MemoryBuffer
. I'm new to C++, candidly trying to guess my way through from a perspective of a little hacking in Python.
I think I've almost figured out how to use an exception handling support from Boost Outcome with regards to the ErrorOr<T>
type from the LLVM support library.
I've defined an extension for the BOOST_OUTCOME_TRY
macro for the type llvm::ErrorOr<std::unique_ptr<T>>
. In a test application, this fails to compile, producing an error message that I honestly don't know how to interpret.
#include <llvm/Support/MemoryBuffer.h>
#include <boost/outcome.hpp>
namespace outcome = BOOST_OUTCOME_V2_NAMESPACE;
BOOST_OUTCOME_V2_NAMESPACE_BEGIN
template<class T>
inline bool try_operation_has_value(const llvm::ErrorOr<std::unique_ptr<T>>& v)
{
return static_cast<bool>(v);
}
template<class T>
inline auto try_return_as(const llvm::ErrorOr<std::unique_ptr<T>>& v)
{
if (!v) {
return failure(v->getError());
}
}
template<class T>
inline auto try_operation_extract_value(
const llvm::ErrorOr<std::unique_ptr<T>>& v)
{
return (*v).get();
}
BOOST_OUTCOME_V2_NAMESPACE_END
int test_stdin()
{
BOOST_OUTCOME_TRY(const auto& ibuff, llvm::MemoryBuffer::getSTDIN());
return 0;
}
This is for an application of llvm::MemoryBuffer
from the LLVM support library. The static method llvm::MemoryBuffer::getSTDIN())
is declared as having a return type ErrorOr<std::unique_ptr<MemoryBuffer>>
After I try to compile this code, the following two items appear under an error squiggly in VS Code, at my application of the BOOST_OUTCOME_TRY
macro.
no instance of overloaded function "boost::outcome_v2::try_operation_return_as" matches the argument listC/C++(304)
main.cpp(78, 3): argument types are: (llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer>>>)
Second item:
no matching function for call to 'try_operation_return_as'GCC
try.hpp(375, 32): expanded from macro 'BOOST_OUTCOME_TRY'
try.hpp(191, 35): expanded from macro 'BOOST_OUTCOME_TRY_CALL_OVERLOAD'
try.hpp(188, 55): expanded from macro 'BOOST_OUTCOME_TRY_OVERLOAD_MACRO'
try.hpp(375, 32): skipping 5 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all
try.hpp(316, 36): expanded from macro 'BOOST_OUTCOME_TRYA'
try.hpp(251, 3): expanded from macro 'BOOST_OUTCOME_TRY2_SUCCESS_LIKELY'
try.hpp(236, 21): expanded from macro 'BOOST_OUTCOME_TRYV2_SUCCESS_LIKELY'
try.hpp(129, 33): candidate template ignored: requirement 'detail::has_as_failure(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
try.hpp(138, 33): candidate template ignored: requirement 'detail::has_assume_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
try.hpp(147, 33): candidate template ignored: requirement 'detail::has_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
More detail, under the same error squiggly location in VS Code. (Maybe there's an explanation here?)
#define BOOST_OUTCOME_TRY(__VA_ARGS__...) BOOST_OUTCOME_TRY_CALL_OVERLOAD(BOOST_OUTCOME_TRY_INVOKE_TRY, __VA_ARGS__)
! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
Expands to:
auto _outcome_try_unique_name_temporary2 = (llvm::MemoryBuffer::getSTDIN()); if(::boost::outcome_v2::try_operation_has_value(_outcome_try_unique_name_temporary2)) [[likely]]; else { auto _outcome_try_unique_name_temporary2_f(::boost::outcome_v2::try_operation_return_as(static_cast<decltype(_outcome_try_unique_name_temporary2) &&>(_outcome_try_unique_name_temporary2))); return _outcome_try_unique_name_temporary2_f; }; const auto& ibuff = ::boost::outcome_v2::try_operation_extract_value(static_cast<decltype(_outcome_try_unique_name_temporary2) &&>(_outcome_try_unique_name_temporary2))
That seems to appear in the compiler output as follows:
[build] /projects/sandbox/cpp_sandbox_10/source/main.cpp:78:3: error: no matching function for call to 'try_operation_return_as'
[build] 78 | BOOST_OUTCOME_TRY(const auto& ibuff, llvm::MemoryBuffer::getSTDIN());
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:375:32: note: expanded from macro 'BOOST_OUTCOME_TRY'
[build] 375 | #define BOOST_OUTCOME_TRY(...) BOOST_OUTCOME_TRY_CALL_OVERLOAD(BOOST_OUTCOME_TRY_INVOKE_TRY, __VA_ARGS__)
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:191:35: note: expanded from macro 'BOOST_OUTCOME_TRY_CALL_OVERLOAD'
[build] 191 | BOOST_OUTCOME_TRY_OVERLOAD_GLUE(BOOST_OUTCOME_TRY_OVERLOAD_MACRO(name, BOOST_OUTCOME_TRY_COUNT_ARGS_MAX8(__VA_ARGS__)), (__VA_ARGS__))
[build] | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:188:55: note: expanded from macro 'BOOST_OUTCOME_TRY_OVERLOAD_MACRO'
[build] 188 | #define BOOST_OUTCOME_TRY_OVERLOAD_MACRO(name, count) BOOST_OUTCOME_TRY_OVERLOAD_MACRO1(name, count)
[build] | ^
[build] note: (skipping 5 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:316:36: note: expanded from macro 'BOOST_OUTCOME_TRYA'
[build] 316 | #define BOOST_OUTCOME_TRYA(v, ...) BOOST_OUTCOME_TRY2_SUCCESS_LIKELY(BOOST_OUTCOME_TRY_UNIQUE_NAME, return, v, __VA_ARGS__)
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:251:3: note: expanded from macro 'BOOST_OUTCOME_TRY2_SUCCESS_LIKELY'
[build] 251 | BOOST_OUTCOME_TRYV2_SUCCESS_LIKELY(unique, retstmt, var, __VA_ARGS__); \
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:236:21: note: expanded from macro 'BOOST_OUTCOME_TRYV2_SUCCESS_LIKELY'
[build] 236 | auto unique##_f(::BOOST_OUTCOME_V2_NAMESPACE::try_operation_return_as(static_cast<decltype(unique) &&>(unique))); \
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:129:33: note: candidate template ignored: requirement 'detail::has_as_failure(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
[build] 129 | constexpr inline decltype(auto) try_operation_return_as(T &&v, detail::as_failure_overload = {})
[build] | ^
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:138:33: note: candidate template ignored: requirement 'detail::has_assume_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
[build] 138 | constexpr inline decltype(auto) try_operation_return_as(T &&v, detail::assume_error_overload = {})
[build] | ^
[build] /opt/miniforge3/envs/cpp_sandbox_10/include/boost/outcome/try.hpp:147:33: note: candidate template ignored: requirement 'detail::has_error(5)' was not satisfied [with T = decltype(_outcome_try_unique_name_temporary0)]
[build] 147 | constexpr inline decltype(auto) try_operation_return_as(T &&v, detail::error_overload = {})
[build] | ^
I think this is centered on how the BOOST_OUTCOME_TRY
macro is being expanded here, using those three functions above as an extension for BOOST_OUTCOME_TRY
.
I wonder if anyone can help to clarify what's failing when that compiles?
I'm hoping that one could be able to reuse this albeit trivial extension onto the boost outcome support, when applying this and other static methods of llvm::MemoryBuffer
. I'm new to C++, candidly trying to guess my way through from a perspective of a little hacking in Python.
2 Answers
Reset to default 4You had several errors compounding.
- The name
try_operation_return_as
was misspelled - It did an invalid indirection in
v->getError()
(instead ofv.getError()
) - It had a branch not returning a value
test_stdin()
did not support error return type, which is required when using BOOST_OUTCOME_TRY.- UPDATE There was a lifetime bug in returning the pointer governed by a
unique_ptr
and using it after theunique_ptr
is destructed. Instead of returning(*v).get()
you should be movingv.get()
itself.
Fixing all of these:
#include <boost/outcome.hpp>
#include <llvm/Support/MemoryBuffer.h>
namespace outcome = boost ::outcome_v2;
namespace boost { namespace outcome_v2 {
template <class T> inline bool try_operation_has_value(llvm::ErrorOr<std::unique_ptr<T>> const& v) {
return static_cast<bool>(v);
}
template <class T> inline auto try_operation_return_as(llvm::ErrorOr<std::unique_ptr<T>>&& v) {
assert(!v);
return failure(std::move(v).getError());
}
template <class T> inline auto try_operation_extract_value(llvm::ErrorOr<std::unique_ptr<T>>&& v) {
return std::move(v.get());
}
}} // namespace boost::outcome_v2
outcome::outcome<int> test_stdin() {
BOOST_OUTCOME_TRY(auto const& ibuff, llvm::MemoryBuffer::getSTDIN());
return ibuff->getBufferSize();
}
int main() {
auto r = test_stdin();
return r ? r.value() : 1;
}
The function should have been named try_operation_return_as
not try_return_as
....