I have a function that scans the user's file system, fills a vector with the paths, then either sorts it or not. Since the user should be able to decide at compile-time whether he wants the vector sorted or not, I use templates and helper classes in place of a much 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've written above is GREATLY simplified from the original, which takes multiple template parameters to allow the user to customize even further the results of the function at compile-time.
Is there an alternative to using all of these helper classes? It gets really messy and hard 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)); }
}
};
Since your value is known at compile time (non-template type parameter) you can perfectly write a "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 perform constant folding and dead code elimination (if those optimisations are enabled, of course), and the result will be exactly the same as if you used the hypothetical static_if
.
I am afraid there has been a misunderstanding about the usage of static_if
.
Certainly you can use static_if
(or whatever trick you wish really) to try and get some optimization, but that is not its first goal.
The first goal of static_if
is semantical. Let me demonstrate this with std::advance
. A typical implementation of std::advance
will use a type switch to choose, at compile time, between an O(1) implementation (for Random Access Iterators) and an O(n) implementation (for the others):
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 just a if
in this case ? Because it would not compile.
+=
--
Thus, the only way to implement the functionality is to statically dispatch to a function only using the available operations on the given type.
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