C ++ metaprogramming template, "static if" workaround - can it be improved?

I have a function that scans a user file system, populates a vector with paths, then either sorts it or not. Since the user should be able to decide at compile time whether he wants to sort the vector or not, I use templates and helper classes instead of the desired (but not existing) "static if".

Consider this code:

enum class Sort{Alphabetic, Unsorted}; template<Sort TS> struct SortHelper; template<> struct SortHelper<Sort::Alphabetic> { static void sort(vector<string>& mTarget) { sort(begin(mTarget), end(mTarget)); } }; template<> struct SortHelper<Sort::Unsorted> { static void sort(vector<string>&) { } }; template<Sort TS> struct DoSomethingHelper { static void(vector<string>& mTarget) { // do something with mTarget SortHelper<TS>::sort(mTarget); } }; 

The code I wrote above is ESPECIALLY simplified from the original , which accepts several template parameters so that the user can further customize the results of the function at compile time.

Is there an alternative to using all of these helper classes? It becomes very dirty and difficult to read.

Ideally, this is what I would like to write:

 enum class Sort{Alphabetic, Unsorted}; template<Sort TS> struct DoSomethingHelper { static void(vector<string>& mTarget) { // do something with mTarget static_if(TS == Sort::Unsorted) { /* do nothing */ } static_if(TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); } } }; 
+7
source share
3 answers

Since your value is known at compile time (type parameter without a template), you can perfectly write "normal" if :

 template<Sort TS> void someFunction(vector<string>& mTarget) { if (TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); } // else if (TS == Sort::Unsorted) {} } 

The compiler will constantly fold and delete dead code (if these optimizations are enabled, of course), and the result will be the same as if you were using a hypothetical static_if .

+17
source

I am afraid that there was a misunderstanding about using static_if .

Of course, you can use static_if (or any trick you really want) to try to get some optimization, but this is not the first goal.

The first target of static_if is semantic . Let me demonstrate this with std::advance . A typical std::advance implementation will use a type switch to choose at compile time between the O (1) implementation (for random access iterators) and the O (n) implementation (for the rest):

 template <typename It, typename D> void advance_impl(It& it, D d, random_access_iterator_tag) { it += d; } template <typename It, typename D> void advance_impl(It& it, D d, bidirectional_iterator_tag) { if (d > D(0)) { for (D i(0); i < d; ++i) { ++it; } } else { for (D i(0); i > d; --i) { --it; } } } template <typename It, typename D> void advance_impl(It& it, D d, input_iterator_tag) { for (D i(0); i < d; ++i) { ++it; } } 

And finally:

 template <typename It, typename D> void advance(It& it, D d) { typename std::iterator_traits<It>::iterator_category c; advance_impl(it, d, c); } 

Why not use only if in this case? Because it will not compile.

  • Bidirectional Iterator does not support +=
  • The input iterator (or forward iterator) does not support --

Thus, the only way to implement functionality is to statically dispatch functions only using the available operations for this type.

+11
source

What about specialized specialization?

 #include <vector> #include <iostream> #include <algorithm> using namespace std; enum class Sort { Alphabetic, Unsorted }; template<Sort TS> struct DoSomethingHelper { static void someFunction(vector<string>& mTarget) {} }; template<> struct DoSomethingHelper<Sort::Unsorted> { static void someFunction(vector<string>& mTarget) { } }; template<> struct DoSomethingHelper<Sort::Alphabetic> { static void someFunction(vector<string>& mTarget) { sort(begin(mTarget), end(mTarget)); } }; int main() { vector<string> v = {{"foo", "bar", "foo2", "superman", ".."}}; DoSomethingHelper<Sort::Alphabetic> helper; helper.someFunction(v); for (string& s : v) { cout << s << endl; } return 0; } 

Edit: I'm an idiot.

0
source

All Articles