Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C++11 type traits to provide alternate inline implementations

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?

like image 519
Miral Avatar asked Nov 04 '16 06:11

Miral


Video Answer


1 Answers

[...] 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 noexceptness 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.

like image 90
skypjack Avatar answered Sep 23 '22 00:09

skypjack