Is the following code pattern reasonable when using traits in templated code where both alternative implementations are always compilable?
Reading the code seems clearer than doing other shenanigans to conditionally compile (but then perhaps I'm just not familiar enough with those shenanigans).
template<typename T> class X { void do_something() noexcept(std::is_nothrow_copy_constructible<T>::value) { if (std::is_nothrow_copy_constructible<T>::value) { // some short code that assumes T's copy constructor won't throw } else { // some longer code with try/catch blocks and more complexity } } // many other methods };
(The added complexity is in part to provide the strong exception guarantee.)
I know this code will work, but is it reasonable to expect the compiler to eliminate the constant-false branches and do inlining etc for the noexcept case (where much simpler than the other case)? I'm hoping for something that would be as efficient in the noexcept case as writing the method with only that first block as body (and vice versa, though I'm less worried about the complex case).
If this isn't the right way to do it, can someone please enlighten me to the recommended syntax?
[...] is it reasonable to expect the compiler to eliminate the constant-false branches and do inlining etc for the noexcept case (where much simpler than the other case)?
It could be, but I wouldn't rely on that for you cannot control it.
If you want to remove the if/else
, you can sfinae the return type and clean up the noexcept
qualifier.
As an example:
template<typename T> class X { template<typename U = T> std::enable_if_t<std::is_nothrow_copy_constructible<T>::value> do_something() noexcept(true) {} template<typename U = T> std::enable_if_t<not std::is_nothrow_copy_constructible<T>::value> do_something() noexcept(false) {} };
The drawbacks are that you have now two member functions template.
Not sure it fits your requirements.
If you are allowed to use features from C++17, if constexpr
is probably the way to go and you don't have to break your method in two member functions anymore.
Another approach could be based on tag-dispatching the noexcept
ness of your type.
As an example:
template<typename T> class X { void do_something(std::true_type) noexcept(true) {} void do_something(std::false_type) noexcept(false) {} void do_something() noexcept(do_something(std::is_nothrow_copy_constructible<T>{})) { do_something(std::is_nothrow_copy_constructible<T>{}); } };
I know, sfinae is not a verb, but to sfinae something sounds just so good.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With