Convert variadic template ints to switch statement - c++

I would like to do the following:
// function that depends on key to do stuff
template <int key>
void bar() {...}
template <int ...Keys>
void foo(int key) {
// WHAT SHOULD BE HERE?
}
std::cin >> key;
foo<1,3,5,7,9>(key);
such that it becomes
template <int ...Key>
void foo(int key) {
switch (key) {
case 1: bar<1>();break;
case 3: bar<3>();break;
case 5: bar<5>();break;
case 7: bar<7>();break;
case 9: bar<9>();break;
default: break;
}
}
How can I generate a switch statement that enumerates all variadic template arguments as an efficient switch statement without manually writing the switch statement?

Compilers can turn chained-ifs into switch statements in assembly.
A binary fold like this:
( [&key]{
if(key==Keys) {
bar<Keys>();
return true;
}
return false;
}()||... );
does what you ask, down to the assembly:
Live example - change the #if clause between 0 and 1 to swap between hand-crafted and generated switch statements.

You could use a parameter pack expansion with an empty/extra foo to close the pack as in the example below.
#include <cstdio>
template <int key>
void bar() {
printf( "%d ", key );
}
template < typename = void >
void foo(int key ) {
}
template <int val, int... Keys >
void foo(int key ) {
if ( val == key ) bar<val>();
else {
foo<Keys...>(key);
}
}
int main() {
for ( int key = 0; key<10; ++key ) {
foo<1,3,5,7,9>(key);
}
}
It prints
Program returned: 0
Program stdout
1 3 5 7 9
Godbolt: https://godbolt.org/z/zE1cE9eob

Following the example of the Yakk's answer, I propose the following solution that, using ternary and comma operators, avoid the lambda
template <int ...Keys>
void foo (int key) {
(void)((Keys == key ? (void)bar<Keys>(), 0 : 0), ...);
}
or, maybe better,
template <int ...Keys>
void foo (int key) {
(void)((Keys == key ? (void)bar<Keys>(), true : false) || ...);
}

Related

If statement isn't checking stored input [duplicate]

A few times in my program, I've had to check if a variable was one of many options. For example
if (num = (<1 or 2 or 3>)) { DO STUFF }
I've messed around with 'OR's, but nothing seems to be right. I've tried
if (num == (1 || 2 || 3))
but it does nothing.
I'd like to conveniently distinguish between several groups. For example
if (num = (1,2,3))
else if (num = (4,5,6))
else if (num = (7,8,9))
Here's a way in C++11, using std::initializer_list:
#include <algorithm>
#include <initializer_list>
template <typename T>
bool is_in(const T& v, std::initializer_list<T> lst)
{
return std::find(std::begin(lst), std::end(lst), v) != std::end(lst);
}
with that, you can do:
if (is_in(num, {1, 2, 3})) { DO STUFF }
It is not very efficient though when not used with built-in types. int will work fine, but if you compare std::string variables for example, the produced code is just awful.
In C++17 however, you can instead use a much more efficient solution that works well with any type:
template<typename First, typename ... T>
bool is_in(First &&first, T && ... t)
{
return ((first == t) || ...);
}
// ...
// s1, s2, s3, s4 are strings.
if (is_in(s1, s2, s3, s4)) // ...
The C++11 version would be very inefficient here, while this version should produce the same code as hand-written comparisons.
If the values you want to check are sufficiently small, you could create a bit mask of the values that you seek and then check for that bit to be set.
Suppose, you care about a couple of groups.
static const unsigned values_group_1 = (1 << 1) | (1 << 2) | (1 << 3);
static const unsigned values_group_2 = (1 << 4) | (1 << 5) | (1 << 6);
static const unsigned values_group_3 = (1 << 7) | (1 << 8) | (1 << 9);
if ((1 << value_to_check) & values_group_1) {
// You found a match for group 1
}
if ((1 << value_to_check) & values_group_2) {
// You found a match for group 2
}
if ((1 << value_to_check) & values_group_3) {
// You found a match for group 3
}
This approach works best for values that don't exceed the natural size your CPU likes to work with. This would typically be 64 in modern times, but may vary depending upon the specifics of your environment.
You have to do the comparison with each value. E.g.
if (num == 1 || num == 2 || num == 3) { stuff }
You may also want to consider a switch and intentionally falling through cases (although I don't think it's the best solution for what you're stating).
switch (num) {
case 1:
case 2:
case 3:
{DO STUFF}
break;
default:
//do nothing.
}
I just had a similar problem and I came to these C++11 solutions:
template <class T>
struct Is
{
T d_;
bool in(T a) {
return a == d_;
}
template <class Arg, class... Args>
bool in(Arg a, Args... args) {
return in(a) || in(args...);
}
};
template <class T>
Is<T> is(T d) {
return Is<T>{d};
}
Or as alternative without the recursion terminating method. Be aware that here the order of comparisons is undefined and that this does not terminate early if the first match is found. But the code is more compact.
template <class T>
struct Is {
const T d_;
template <class... Args>
bool in(Args... args) {
bool r{ false };
[&r](...){}(( (r = r || d_ == args), 1)...);
return r;
}
};
template <class T>
Is<T> is(T d) {
return Is<T>{d};
}
So for both solutions the code would look like:
if (is(num).in(1,2,3)) {
// do whatever needs to be done
}
You can define a set of integers, add the desired values to it, and then use the find method to see if the value in question is in the set
std::set<int> values;
// add the desired values to your set...
if (values.find(target) != values.end())
...
I needed to do something similar for enums. I have a variable and wish to test it against a ranges of values.
Here I've used a variadic template function. Note the specialisation for const char* type, so that is_in( my_str, "a", "b", "c") has the expected outcome for when my_str stores "a".
#include <cstring>
template<typename T>
constexpr bool is_in(T t, T v) {
return t == v;
}
template<>
constexpr bool is_in(const char* t, const char* v) {
return std::strcmp(t,v);
}
template<typename T, typename... Args>
constexpr bool is_in(T t, T v, Args... args) {
return t==v || is_in(t,args...);
}
Example usage:
enum class day
{
mon, tues, wed, thur, fri, sat, sun
};
bool is_weekend(day d)
{
return is_in(d, day::sat, day::sun);
}
float n;
if (n<1) exit(0);
if (n / 3 <= 1)
// within 1, 2, 3
else if (n / 3 <= 2)
// within 4, 5, 6
else if (n / 3 <= 3)
// within 7, 8, 9

how to tell if a enum class value is in a specified range of enum class in a more effective way? [duplicate]

A few times in my program, I've had to check if a variable was one of many options. For example
if (num = (<1 or 2 or 3>)) { DO STUFF }
I've messed around with 'OR's, but nothing seems to be right. I've tried
if (num == (1 || 2 || 3))
but it does nothing.
I'd like to conveniently distinguish between several groups. For example
if (num = (1,2,3))
else if (num = (4,5,6))
else if (num = (7,8,9))
Here's a way in C++11, using std::initializer_list:
#include <algorithm>
#include <initializer_list>
template <typename T>
bool is_in(const T& v, std::initializer_list<T> lst)
{
return std::find(std::begin(lst), std::end(lst), v) != std::end(lst);
}
with that, you can do:
if (is_in(num, {1, 2, 3})) { DO STUFF }
It is not very efficient though when not used with built-in types. int will work fine, but if you compare std::string variables for example, the produced code is just awful.
In C++17 however, you can instead use a much more efficient solution that works well with any type:
template<typename First, typename ... T>
bool is_in(First &&first, T && ... t)
{
return ((first == t) || ...);
}
// ...
// s1, s2, s3, s4 are strings.
if (is_in(s1, s2, s3, s4)) // ...
The C++11 version would be very inefficient here, while this version should produce the same code as hand-written comparisons.
If the values you want to check are sufficiently small, you could create a bit mask of the values that you seek and then check for that bit to be set.
Suppose, you care about a couple of groups.
static const unsigned values_group_1 = (1 << 1) | (1 << 2) | (1 << 3);
static const unsigned values_group_2 = (1 << 4) | (1 << 5) | (1 << 6);
static const unsigned values_group_3 = (1 << 7) | (1 << 8) | (1 << 9);
if ((1 << value_to_check) & values_group_1) {
// You found a match for group 1
}
if ((1 << value_to_check) & values_group_2) {
// You found a match for group 2
}
if ((1 << value_to_check) & values_group_3) {
// You found a match for group 3
}
This approach works best for values that don't exceed the natural size your CPU likes to work with. This would typically be 64 in modern times, but may vary depending upon the specifics of your environment.
You have to do the comparison with each value. E.g.
if (num == 1 || num == 2 || num == 3) { stuff }
You may also want to consider a switch and intentionally falling through cases (although I don't think it's the best solution for what you're stating).
switch (num) {
case 1:
case 2:
case 3:
{DO STUFF}
break;
default:
//do nothing.
}
I just had a similar problem and I came to these C++11 solutions:
template <class T>
struct Is
{
T d_;
bool in(T a) {
return a == d_;
}
template <class Arg, class... Args>
bool in(Arg a, Args... args) {
return in(a) || in(args...);
}
};
template <class T>
Is<T> is(T d) {
return Is<T>{d};
}
Or as alternative without the recursion terminating method. Be aware that here the order of comparisons is undefined and that this does not terminate early if the first match is found. But the code is more compact.
template <class T>
struct Is {
const T d_;
template <class... Args>
bool in(Args... args) {
bool r{ false };
[&r](...){}(( (r = r || d_ == args), 1)...);
return r;
}
};
template <class T>
Is<T> is(T d) {
return Is<T>{d};
}
So for both solutions the code would look like:
if (is(num).in(1,2,3)) {
// do whatever needs to be done
}
You can define a set of integers, add the desired values to it, and then use the find method to see if the value in question is in the set
std::set<int> values;
// add the desired values to your set...
if (values.find(target) != values.end())
...
I needed to do something similar for enums. I have a variable and wish to test it against a ranges of values.
Here I've used a variadic template function. Note the specialisation for const char* type, so that is_in( my_str, "a", "b", "c") has the expected outcome for when my_str stores "a".
#include <cstring>
template<typename T>
constexpr bool is_in(T t, T v) {
return t == v;
}
template<>
constexpr bool is_in(const char* t, const char* v) {
return std::strcmp(t,v);
}
template<typename T, typename... Args>
constexpr bool is_in(T t, T v, Args... args) {
return t==v || is_in(t,args...);
}
Example usage:
enum class day
{
mon, tues, wed, thur, fri, sat, sun
};
bool is_weekend(day d)
{
return is_in(d, day::sat, day::sun);
}
float n;
if (n<1) exit(0);
if (n / 3 <= 1)
// within 1, 2, 3
else if (n / 3 <= 2)
// within 4, 5, 6
else if (n / 3 <= 3)
// within 7, 8, 9

Default value for template function argument

Caution: I don't have C++11
I need a default value for a template function parameter, but it seems c++
will skip deduction for default parameters...
struct mode1 {};
struct mode2 {};
template <typename T>
void myFunc(int value, T mode = mode1())
{
if(std::is_same<T, mode1>::value)
{
std::cout << "foo";
}
else if(std::is_same<T, mode2>::value)
{
std::cout << "bar";
}
}
But how can i achieve, that this call will work:
myFunc(20); /* Defaults to mode1 */
Why i will use this? Because of optimization...
In my real life scenario, i would use this for this piece of code:
template <typename TokenType>
HGStringBasic Tokenize(const _ElemT* tokens, size_type uTokenIndex, size_type uIndex = 0, size_type uEndIndex = npos, TokenType tokenType = tokenTypeChar()) const
{
size_type uPosInStr;
size_type uCurrToken;
if(uEndIndex == npos)
{
uEndIndex = this->Length();
}
for( uCurrToken = 0 ; uIndex < uEndIndex ; (uIndex = uPosInStr+1), (++uCurrToken) )
{
if(std::is_same<TokenType, tokenTypeChar>::value)
uPosInStr = this->PosBrk(tokens, uIndex);
else if(std::is_same<TokenType, tokenTypeString>::value)
uPosInStr = this->Pos(tokens, uIndex);
if(uCurrToken == uTokenIndex)
{
if(uPosInStr == npos)
return this_type(&m_data[uIndex], uEndIndex - uIndex);
return this_type(&m_data[uIndex], (uPosInStr < uEndIndex ? uPosInStr : uEndIndex) - uIndex);
}
if(uPosInStr == npos)
break;
}
return this_type();
}
Yes, default value is not considered in template arugment deduction.
Type template parameter cannot be deduced from the type of a function default argument
You can add an overload, e.g.
template <typename T>
void myFunc(int value, T mode)
{
...
}
void myFunc(int value) {
myFunc(value, mode1());
}

Optimize C++ template executions

I am working on project where the performance is critical. The application is processing a huge amount of data. Code is written in C++ and I need to do some changes.
There is given following code (It is NOT my code and I simplified it to minimum):
void process<int PARAM1, int PARAM2>() {
// processing the data
}
void processTheData (int param1, int param2) { // wrapper
if (param1 == 1 && param2 == 1) { // Ugly looking block of if's
process<1, 1>();
else if(param1 == 1 && param2 == 2) {
process<1, 2>();
else if(param1 == 1 && param2 == 3) {
process<1, 3>();
else if(param1 == 1 && param2 == 4) {
process<1, 4>();
else if(param1 == 2 && param2 == 1) {
process<2, 1>();
else if(param1 == 2 && param2 == 2) {
process<2, 2>();
else if(param1 == 2 && param2 == 3) {
process<2, 3>();
else if(param1 == 2 && param2 == 4) {
process<2, 4>();
} // and so on....
}
And the main function:
int main(int argc, char *argv[]) {
factor1 = atoi(argv[1]);
factor2 = atoi(argv[2]);
// choose some optimal param1 and param2
param1 = choseTheOptimal(factor1, factor2);
param2 = choseTheOptimal(factor1, factor2);
processTheData(param1, param2); //start processing
return 0;
}
Hopefully the code looks clear.
The functions:
process is the core function that is processing the data,
processTheData is a wrapper of the process function.
There is a limited number of values that the params (param1 and param2) takes (Let's say about 10 x 10).
The values of param1 and param2 are NOT known before execution.
If I simply rewrite the process function so it uses the function parameters instead of template constants (means process(int PARAM1, int PARAM2)) then the processing is about 10 times slower.
Because of the above the PARAM1 and PARAM2 must be the constant of process function.
Is there any smart way to get rid of this ugly block of if's located in processTheData function?
Like this.
#include <array>
#include <utility>
template<int PARAM1, int PARAM2>
void process() {
// processing the data
}
// make a jump table to call process<X, Y> where X is known and Y varies
template<std::size_t P1, std::size_t...P2s>
constexpr auto make_table_over_p2(std::index_sequence<P2s...>)
{
return std::array<void (*)(), sizeof...(P2s)>
{
&process<int(P1), int(P2s)>...
};
}
// make a table of jump tables to call process<X, Y> where X and Y both vary
template<std::size_t...P1s, std::size_t...P2s>
constexpr auto make_table_over_p1_p2(std::index_sequence<P1s...>, std::index_sequence<P2s...> p2s)
{
using element_type = decltype(make_table_over_p2<0>(p2s));
return std::array<element_type, sizeof...(P1s)>
{
make_table_over_p2<P1s>(p2s)...
};
}
void processTheData (int param1, int param2) { // wrapper
// make a 10x10 jump table
static const auto table = make_table_over_p1_p2(
std::make_index_sequence<10>(),
std::make_index_sequence<10>()
) ;
// todo - put some limit checks here
// dispatch
table[param1][param2]();
}
This is what I call the matic switch. It takes a runtime value (within a specified range), and turns it into a compile time value.
namespace details
{
template<std::size_t I>
using index_t = std::integral_constant<std::size_t, I>;
template<class F>
using f_result = std::result_of_t< F&&(index_t<0>) >;
template<class F>
using f_ptr = f_result<F>(*)(F&& f);
template<class F, std::size_t I>
f_ptr<F> get_ptr() {
return [](F&& f)->f_result<F> {
return std::forward<F>(f)(index_t<I>{});
};
}
template<class F, std::size_t...Is>
auto dispatch( F&& f, std::size_t X, std::index_sequence<Is...> ) {
static const f_ptr<F> table[]={
get_ptr<F, Is>()...
};
return table[X](std::forward<F>(f));
}
}
template<std::size_t max, class F>
details::f_result<F>
dispatch( F&& f, std::size_t I ) {
return details::dispatch( std::forward<F>(f), I, std::make_index_sequence<max>{} );
}
what this does is build a jump table to convert runtime data to a compile time constant. I use a lambda, because it makes it nice and generic, and pass it an integral constant. An integral constant is a runtime stateless object whose type carries the constant with it.
An example use:
template<std::size_t a, std::size_t b>
void process() {
static_assert( sizeof(int[a+1]) + sizeof(int[b+1]) >= 0 );
}
constexpr int max_factor_1 = 10;
constexpr int max_factor_2 = 10;
int main() {
int factor1 = 1;
int factor2 = 5;
dispatch<max_factor_1>(
[factor2](auto factor1) {
dispatch<max_factor_2>(
[factor1](auto factor2) {
process< decltype(factor1)::value, decltype(factor2)::value >();
},
factor2
);
},
factor1
);
}
where max_factor_1 and max_factor_2 are constexpr values or expressions.
This uses C++14 for auto lambdas and constexpr implicit cast from integral constants.
Live example.
This is what I came up with. It uses less fancy features (only enable_if, no variadic templates or function pointers) but it is also less generic. Pasting the code into godbolt indicates that compilers are able to optimize this completely away for the example code which may have a performance advantage in the real code.
#include <type_traits>
template <int param1, int param2>
void process() {
static_assert(sizeof(int[param1 + 1]) + sizeof(int[param2 + 1]) > 0);
}
template <int limit2, int param1, int param2>
std::enable_if_t<(param2 > limit2)> pick_param2(int) {
static_assert("Invalid value for parameter 2");
}
template <int limit2, int param1, int param2>
std::enable_if_t<param2 <= limit2> pick_param2(int p) {
if (p > 0) {
pick_param2<limit2, param1, param2 + 1>(p - 1);
} else {
process<param1, param2>();
}
}
template <int limit1, int limit2, int param>
std::enable_if_t<(param > limit1)> pick_param1(int, int) {
static_assert("Invalid value for parameter 1");
}
template <int limit1, int limit2, int param>
std::enable_if_t<param <= limit1> pick_param1(int p1, int p2) {
if (p1 > 0) {
pick_param1<limit1, limit2, param + 1>(p1 - 1, p2);
} else {
pick_param2<limit2, param, 0>(p2);
}
}
template <int limit_param1, int limit_param2>
void pick_params(int param1, int param2) {
pick_param1<limit_param1, limit_param2, 0>(param1, param2);
}
int main() {
int p1 = 3;
int p2 = 5;
pick_params<10, 10>(p1, p2);
}
I'd be interested in profiling results.

C++ Check if one of multple values lower than int [duplicate]

A few times in my program, I've had to check if a variable was one of many options. For example
if (num = (<1 or 2 or 3>)) { DO STUFF }
I've messed around with 'OR's, but nothing seems to be right. I've tried
if (num == (1 || 2 || 3))
but it does nothing.
I'd like to conveniently distinguish between several groups. For example
if (num = (1,2,3))
else if (num = (4,5,6))
else if (num = (7,8,9))
Here's a way in C++11, using std::initializer_list:
#include <algorithm>
#include <initializer_list>
template <typename T>
bool is_in(const T& v, std::initializer_list<T> lst)
{
return std::find(std::begin(lst), std::end(lst), v) != std::end(lst);
}
with that, you can do:
if (is_in(num, {1, 2, 3})) { DO STUFF }
It is not very efficient though when not used with built-in types. int will work fine, but if you compare std::string variables for example, the produced code is just awful.
In C++17 however, you can instead use a much more efficient solution that works well with any type:
template<typename First, typename ... T>
bool is_in(First &&first, T && ... t)
{
return ((first == t) || ...);
}
// ...
// s1, s2, s3, s4 are strings.
if (is_in(s1, s2, s3, s4)) // ...
The C++11 version would be very inefficient here, while this version should produce the same code as hand-written comparisons.
If the values you want to check are sufficiently small, you could create a bit mask of the values that you seek and then check for that bit to be set.
Suppose, you care about a couple of groups.
static const unsigned values_group_1 = (1 << 1) | (1 << 2) | (1 << 3);
static const unsigned values_group_2 = (1 << 4) | (1 << 5) | (1 << 6);
static const unsigned values_group_3 = (1 << 7) | (1 << 8) | (1 << 9);
if ((1 << value_to_check) & values_group_1) {
// You found a match for group 1
}
if ((1 << value_to_check) & values_group_2) {
// You found a match for group 2
}
if ((1 << value_to_check) & values_group_3) {
// You found a match for group 3
}
This approach works best for values that don't exceed the natural size your CPU likes to work with. This would typically be 64 in modern times, but may vary depending upon the specifics of your environment.
You have to do the comparison with each value. E.g.
if (num == 1 || num == 2 || num == 3) { stuff }
You may also want to consider a switch and intentionally falling through cases (although I don't think it's the best solution for what you're stating).
switch (num) {
case 1:
case 2:
case 3:
{DO STUFF}
break;
default:
//do nothing.
}
I just had a similar problem and I came to these C++11 solutions:
template <class T>
struct Is
{
T d_;
bool in(T a) {
return a == d_;
}
template <class Arg, class... Args>
bool in(Arg a, Args... args) {
return in(a) || in(args...);
}
};
template <class T>
Is<T> is(T d) {
return Is<T>{d};
}
Or as alternative without the recursion terminating method. Be aware that here the order of comparisons is undefined and that this does not terminate early if the first match is found. But the code is more compact.
template <class T>
struct Is {
const T d_;
template <class... Args>
bool in(Args... args) {
bool r{ false };
[&r](...){}(( (r = r || d_ == args), 1)...);
return r;
}
};
template <class T>
Is<T> is(T d) {
return Is<T>{d};
}
So for both solutions the code would look like:
if (is(num).in(1,2,3)) {
// do whatever needs to be done
}
You can define a set of integers, add the desired values to it, and then use the find method to see if the value in question is in the set
std::set<int> values;
// add the desired values to your set...
if (values.find(target) != values.end())
...
I needed to do something similar for enums. I have a variable and wish to test it against a ranges of values.
Here I've used a variadic template function. Note the specialisation for const char* type, so that is_in( my_str, "a", "b", "c") has the expected outcome for when my_str stores "a".
#include <cstring>
template<typename T>
constexpr bool is_in(T t, T v) {
return t == v;
}
template<>
constexpr bool is_in(const char* t, const char* v) {
return std::strcmp(t,v);
}
template<typename T, typename... Args>
constexpr bool is_in(T t, T v, Args... args) {
return t==v || is_in(t,args...);
}
Example usage:
enum class day
{
mon, tues, wed, thur, fri, sat, sun
};
bool is_weekend(day d)
{
return is_in(d, day::sat, day::sun);
}
float n;
if (n<1) exit(0);
if (n / 3 <= 1)
// within 1, 2, 3
else if (n / 3 <= 2)
// within 4, 5, 6
else if (n / 3 <= 3)
// within 7, 8, 9