the code below prints val2 on both f() calls. What would be a proper way to execute specific branch in f() based on enum value ?
enum class E
{
val1,
val2
};
using val1_t = std::integral_constant<E, E::val1>;
using val2_t = std::integral_constant<E, E::val2>;
template <typename T>
void f(T t)
{
if constexpr (std::is_same_v<T, val1_t>)
{
std::cerr << "val1\n";
}
else
{
std::cerr << "val2\n";
}
}
int main()
{
f(E::val1);
f(E::val2);
}
If you move the enum into the template parameter, then you could use
template <E val>
void f()
{
if constexpr (val == E::val1)
{
std::cerr << "val1\n";
}
else
{
std::cerr << "val2\n";
}
}
And you would use it like
int main()
{
f<E::val1>();
f<E::val2>();
}
Related
I have many functions q1, q2, q3, etc., each with a different return type (int, int64_t, std::string, etc.).
I also have a print_result function that prints out their results (and the time they take to run, but trimmed here for simplicity):
template <typename T>
void print_result(T (*func)()) {
T res = func();
std::cout << res << std::endl;
}
I also have big switch statement to print the result for each of the functions:
switch (question_num) {
case 1: print_result(q1); break;
case 2: print_result(q2); break;
case 3: print_result(q3); break;
// ...
}
Objective: I would like to replace this switch statement with a template function, to avoid copying each line every time I add a new function.
I have tried to look at C++ template instantiation: Avoiding long switches, but I'm new to template metaprogramming, so not sure how to handle this exactly.
My current attempt that doesn't compile:
template <<int, typename> ...> struct FuncList {};
template <typename T>
bool handle_cases(int, T, FuncList<>) {
// default case
return false;
}
template <<int I, typename T> ...S>
bool handle_cases(int i, T (*func)(), FuncList<T, S...>) {
if (I != i) {
return handle_cases(i, func, FuncList<S...>());
}
print_result(func);
return true;
}
template <typename ...S>
bool handle_cases(int i, T (*func)()) {
return handle_cases(i, func, FuncList<S...>());
}
// ...
bool res = handle_cases<
<1, q1>, <2, q2>, <3, q3>
>(question_num);
// ...
My ideal way of using this template is shown at the last line there.
Note that the mappings from the function number to the function is provided there. The function numbers are fixed, i.e. q1 maps to the constant 1 and that won't change at runtime.
The compilation error (it might be rather basic but I really don't know much about metaprogramming):
error: expected unqualified-id before ‘<<’ token
17 | template <<int, typename> ...> struct FuncList {};
| ^~
If you can use c++17, here's a "simplified" version of #Klaus's approach. Instead of using a had-made recursive structure, you could use a c++17 fold-expression:
template<auto... Funcs, std::size_t... I>
bool select_case(std::size_t i, std::integer_sequence<std::size_t, I...>) {
return ([&]{ if(i == I) { print_result(Funcs); return true; } return false; }() || ... );
}
template<auto... Funcs>
struct FuncSwitch {
static bool Call(std::size_t i) {
return select_case<Funcs...>(i, std::make_index_sequence<sizeof...(Funcs)>());
}
};
The idea is to wrap each of Funcs in a lambda such that only the function corresponding to the index passed is called. Note that the || in the fold expression short-circuits.
Would be used like this:
float q0() { return 0.f; }
int q1() { return 1; }
std::string q2() { return "two"; }
int main() {
bool success = FuncSwitch<q0, q1, q2>::Call(1);
}
See here for a complete example.
I've got a different proposal:
Use an std::array instead of switch (or std::map if the switch cases are non-continuous, std::array has O(1) access time, std::map O(log(n)) and switch O(n).
Use std::function and std::bind to bind your functions you want to call to a functor object
use the index into the array to call the function
Use placeholders if you need to pass additional data
#include <iostream>
#include <functional>
template <typename T>
void print_result(T (*func)()) {
T res = func();
std::cout << res << std::endl;
}
int int_function() {
return 3;
}
double double_function() {
return 3.5;
}
std::array<std::function<void()>, 2> functions({
std::bind(print_result<int>, int_function),
std::bind(print_result<double>, double_function),
});
int main() {
functions[0]();
functions[1]();
return 0;
}
Output:
3
3.5
See: Why does std::function can implicit convert to a std::function which has more parameter?
Update:
With parameter passing:
#include <iostream>
#include <functional>
template <typename T>
void print_result(T (*func)(int), int value) {
T res = func(value);
std::cout << res << std::endl;
}
int int_function(int value) {
return 3 * value;
}
double double_function(int value) {
return 3.5 * value;
}
std::array<std::function<void(int)>, 2> functions({
std::bind(print_result<int>, int_function, std::placeholders::_1),
std::bind(print_result<double>, double_function, std::placeholders::_1),
});
int main() {
functions[0](10);
functions[1](11);
return 0;
}
Output:
30
38.5
You may like a version which do not need any kind of runtime containers, did not generate any objects in between and even do not generate a data table and generates very less code and is also easy to use:
// Example functions
int fint() { return 1; }
double fdouble() { return 2.2; }
std::string fstring() { return "Hallo"; }
// your templated result printer
template < typename T>
void print_result( T parm )
{
std::cout << "The result of call is " << parm << std::endl;
}
// lets create a type which is able to hold functions
template < auto ... FUNCS >
struct FUNC_CONTAINER
{
static constexpr unsigned int size = sizeof...(FUNCS);
};
// and generate a interface to switch
template < unsigned int, typename T >
struct Switch_Impl;
template < unsigned int IDX, auto HEAD, auto ... TAIL >
struct Switch_Impl< IDX, FUNC_CONTAINER<HEAD, TAIL...>>
{
static void Do( unsigned int idx )
{
if ( idx == IDX )
{
// Your function goes here
print_result(HEAD());
}
else
{
if constexpr ( sizeof...(TAIL))
{
Switch_Impl< IDX+1, FUNC_CONTAINER<TAIL...>>::Do(idx);
}
}
}
};
// a simple forwarder to simplify the interface
template < typename T>
struct Switch
{
static void Do(unsigned int idx )
{
Switch_Impl< 0, T >::Do( idx );
}
};
// and lets execute the stuff
int main()
{
using FUNCS = FUNC_CONTAINER< fint, fdouble, fstring >;
for ( unsigned int idx = 0; idx< FUNCS::size; idx++ )
{
Switch<FUNCS>::Do(idx);
}
}
Given you "current attempt"... it seems to me that you could write a handle_cases struct/class almost as follows
struct handle_cases
{
std::map<int, std::function<void()>> m;
template <typename ... F>
handle_cases (std::pair<int, F> const & ... p)
: m{ {p.first, [=]{ print_result(p.second); } } ... }
{ }
void operator() (int i)
{ m[i](); }
};
with a map between an integer and a lambda that call print_result with the function and an operator() that call the requested lambda, given the corresponding index.
You can create an object of the class as follows (unfortunately I don't see a way to avoid the std::make_pair()s)
handle_cases hc{ std::make_pair(10, q1),
std::make_pair(20, q2),
std::make_pair(30, q3),
std::make_pair(40, q4) };
and using it as follows
hc(30);
The following is a full compiling example
#include <functional>
#include <map>
#include <iostream>
template <typename T>
void print_result (T(*func)())
{
T res = func();
std::cout << res << std::endl;
}
struct handle_cases
{
std::map<int, std::function<void()>> m;
template <typename ... F>
handle_cases (std::pair<int, F> const & ... p)
: m{ {p.first, [=]{ print_result(p.second); } } ... }
{ }
void operator() (int i)
{ m[i](); }
};
char q1 () { return '1'; }
int q2 () { return 2; }
long q3 () { return 3l; }
long long q4 () { return 4ll; }
int main ()
{
handle_cases hc{ std::make_pair(10, q1),
std::make_pair(20, q2),
std::make_pair(30, q3),
std::make_pair(40, q4) };
hc(30);
}
Below I am trying to get a simple max value from a list of traits containing SOME_VAL at compile time:
struct A_Traits { enum { SOME_VAL=5 }; };
struct B_Traits { enum { SOME_VAL=6 }; };
struct C_Traits { enum { SOME_VAL=4 }; };
template<typename T>
T MAX(T t1, T t2)
{
return t1>t2?t1:t2;
}
template<typename T, typename... Args>
struct max_calculator
{
enum { MAX_VAL = MAX(max_calculator<typename T::SOME_VAL>::MAX_VAL, // line 65
max_calculator<Args...>::MAX_VAL) };
};
template<typename T>
struct max_calculator<T>
{
enum { MAX_VAL = T::SOME_VAL };
};
int main()
{
cout << max_calculator<A_Traits>::MAX_VAL << endl;
cout << max_calculator<A_Traits, B_Traits>::MAX_VAL << endl; // line 79
}
However I get a compile error of:
variadic.cpp: In instantiation of 'struct max_calculator<A_Traits, B_Traits>':
variadic.cpp:79:47: required from here
variadic.cpp:65:10: error: no type named 'SOME_VAL' in 'struct A_Traits'
Any idea whats wrong or better ideas to do the same at compile time?
std::max has a constexpr overload for std::initialiser_list<T>, you can expand your pack in one place
template<typename... Args>
struct max_calculator
{
enum { MAX_VAL = std::max({ Args::SOME_VAL... }) };
};
For the benefit of everyone visting this later - the fixed program based on Piotr's answers in the comments section is:
struct A_Traits { enum { SOME_VAL=5 }; };
struct B_Traits { enum { SOME_VAL=6 }; };
struct C_Traits { enum { SOME_VAL=4 }; };
template<typename T>
constexpr T MAX(T t1, T t2)
{
return t1>t2?t1:t2;
}
template<typename T, typename... Args>
struct max_calculator
{
enum { MAX_VAL =MAX<uint8_t>(max_calculator<T>::MAX_VAL,
max_calculator<Args...>::MAX_VAL) };
};
template<typename T>
struct max_calculator<T>
{
enum { MAX_VAL = T::SOME_VAL };
};
int main()
{
cout << max_calculator<A_Traits>::MAX_VAL << endl;
cout << max_calculator<A_Traits, B_Traits>::MAX_VAL << endl;
cout << max_calculator<A_Traits, B_Traits, C_Traits>::MAX_VAL << endl;
}
I have the following code, where I am trying to factor out a switch statement which converts an enum to a templated function call.
I managed to get it working by introducing a helper class, but the result is not very simple or pretty.
Can you think of a more elegant solution?
#include <iostream>
enum Type {kA, kB};
struct A {
static void process(int arg) { std::cerr << "A::process(" << arg << ")\n"; }
};
struct B {
static void process(int arg) { std::cerr << "B::process(" << arg << ")\n"; }
};
// This is the original struct which contains the switch statement.
// However I have several such classes and methods, so I would like to
// factor out the switch().
struct S1 {
template <typename T> void templated_func(int arg) {
T::process(arg + 10 + i_);
T::process(arg + 20 + i_);
}
void func(Type type, int arg) {
switch (type) {
case kA:
templated_func<A>(arg);
break;
case kB:
templated_func<B>(arg);
break;
}
}
int i_ = 100;
};
// This function call dispatches to a templated helper class based
// on the value of the enum type.
template <template <typename T> class HelperClass, typename... Args>
void dispatch(Type type, Args&&... args) {
switch (type) {
case kA:
HelperClass<A>::method(std::forward<Args>(args)...);
break;
case kB:
HelperClass<B>::method(std::forward<Args>(args)...);
break;
}
}
// It works but the result is not simple or pretty. Can it be made simpler somehow?
struct S2 {
template <typename T> void templated_func(int arg) {
T::process(arg + 10 + i_);
T::process(arg + 20 + i_);
}
template <typename T> struct Helper_func {
static void method(S2* pthis, int arg) {
pthis->templated_func<T>(arg);
}
};
void func(Type type, int arg) {
dispatch<S2::Helper_func>(type, this, arg);
}
int i_ = 100;
};
int main() {
S1 s1;
s1.func(kA, 1); // prints A::process(111), A::process(121)
S2 s2;
s2.func(kB, 2); // prints B::process(112), B::process(122)
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Extending enums in C++?
I am using a library which defines its own set of errors as an enum type.
enum error_type {...}
The library also has a function which takes that enum type, and prints the error.
void set_status(error_type new_error)
If I want to define my own error, and give it to the set_status function, is it possible to extend the error_type enum somehow, or maybe override it?
There might be some sharp edges, but I think this should work for you:
#include<iostream>
// Helper struct
template<typename T, int N, typename... LIST>
struct whereInType {
static const int index = -1;
};
template<typename T, int N, typename HEAD, typename... TAIL>
struct whereInType<T,N,HEAD,TAIL...> {
static const int index = whereInType<T, N+1, TAIL...>::index;
};
template<typename T, int N, typename... TAIL>
struct whereInType<T,N,T,TAIL...> {
static const int index = N;
};
// The actual union type
template<typename... ENUMS>
class enum_union {
public:
template<typename ENUM>
constexpr enum_union(ENUM val) :
which_enum(whereInType<ENUM,0,ENUMS...>::index),
value(val) {}
constexpr operator long long(){
return static_cast<long long>(which_enum)<<32 | value;
}
template<typename ENUM, int IGNORE=0>
constexpr bool operator==(const ENUM& e) {
return *this == enum_union<ENUMS...>(e);
}
template<int IGNORE=0>
constexpr bool operator==(const enum_union<ENUMS...>& oth) {
return which_enum==oth.which_enum && value==oth.value;
}
template<typename T>
constexpr bool operator!=(const T& oth) {
return !(*this == oth);
}
private:
int which_enum;
int value;
};
// An example usage
enum normal_errors {
E_OUTOFMEMORY,
E_IOERROR
};
enum weird_errors {
E_OUTOFAARDVARKS,
E_DIVIDEBYCUCUMBER
};
typedef enum_union<normal_errors, weird_errors> any_error;
// Some tests
void print(any_error e) {
switch(e) {
case any_error(E_OUTOFMEMORY):
std::cout << "Out of Memory\n";
break;
case any_error(E_IOERROR):
std::cout << "I/O Error\n";
break;
case any_error(E_OUTOFAARDVARKS):
std::cout << "WE NEED AARDVARKS!!! NOW!!!!!\n";
break;
case any_error(E_DIVIDEBYCUCUMBER):
std::cout << "please reinstall universe\n";
break;
}
}
main(){
print(E_OUTOFMEMORY);
print(E_IOERROR);
print(E_OUTOFAARDVARKS);
print(E_DIVIDEBYCUCUMBER);
if (any_error(E_OUTOFMEMORY) == E_OUTOFAARDVARKS) {
std::cout<<"bad\n";
}else{
std::cout<<"good\n";
}
if (any_error(E_OUTOFMEMORY) != E_OUTOFAARDVARKS) {
std::cout<<"good\n";
}else{
std::cout<<"bad\n";
}
if (any_error(E_OUTOFMEMORY) == E_OUTOFMEMORY) {
std::cout<<"good\n";
}else{
std::cout<<"bad\n";
}
if (any_error(E_OUTOFMEMORY) != E_OUTOFMEMORY) {
std::cout<<"bad\n";
}else{
std::cout<<"good\n";
}
}
I'd like to write a templated function which changes its behavior depending on template class types passed in. To do this, I'd like to determine the type passed in. For example, something like this:
template <class T>
void foo() {
if (T == int) { // Sadly, this sort of comparison doesn't work
printf("Template parameter was int\n");
} else if (T == char) {
printf("Template parameter was char\n");
}
}
Is this possible?
This is the purpose of template specialization, a search for that term gives tons of examples.
#include <iostream>
template <typename T>
void foo()
{
std::cout << "Unknown type " << typeid(T).name() << "\n";
}
template<typename T>
void fooT(T const& x) { foo<T>(); }
template<>
void foo<int>()
{ printf("Template parameter was int\n");
}
template<>
void foo<char>()
{ printf("Template parameter was char\n");
}
int main()
{
fooT(std::cout);
fooT(5);
fooT('a');
fooT("Look Here");
}
By using the power of partial specialization, this can be done at compile time:
template<class T, class U>
struct is_same_type
{
static const bool value = false;
};
template<class T>
struct is_same_type<T, T>
{
static const bool value = true;
};
template <class T>
void foo()
{
if (is_same_type<T, int>::value)
{
printf("Template parameter was int\n");
}
else if (is_same_type<T, char>::value)
{
printf("Template parameter was char\n");
}
}
Compiled in my head, but should work nonetheless.
Using template specialization or typeid would probably work for you, although you might prefer template specialization as it won't incur the runtime cost of typeid. For example:
#include <iostream>
#include <typeinfo>
template <typename T>
void foo(T arg) {
if (typeid(arg) == typeid(int)) std::cout << "foo<T> where T is int\n";
else if (typeid(arg) == typeid(double)) std::cout << "foo<T> where T is double\n";
else if (typeid(arg) == typeid(char)) std::cout << "foo<T> where T is char\n";
}
template <>
void foo<int>(int arg) {
std::cout << "foo<int>\n";
}
int main() {
foo(3); // foo<int>
foo(3.0); // foo<T> where T is double
foo('c'); // foo<T> where T is char
}
Use type_info directly, or better still typeid operator to do that.
#include <typeinfo>
template < typename T >
T max( T arg1, T arg2 ) {
cout << typeid( T ).name() << "s compared." << endl;
return ( arg1 > arg2 ? arg1 : arg2 );
}