in principle the question is about the best way of getting reflexive iteration over an enum at compile time.
Let's assume I have an enum
enum Animal {
DOG = 0,
CAT = 12,
};
Now I have a function template
template <Animal A>
void animalVoice();
And I specialise the template:
template <>
void animalVoice<DOG>() {cout << "Bau" << endl;}
template <>
void animalVoice<CAT>() {cout << "Meow" << endl;}
Do I have the possibility of getting the same behaviour as in
int main() {
animalVoice<DOG>;
animalVoice<CAT>;
return 0;
}
By iterating at compile time over the value of the enum?
Thanks
M.
You might have an animal container:
enum Animal {
DOG = 0,
CAT
};
constexpr auto all_animals = std::integer_sequence<Animal, DOG, CAT>{};
and then
template <Animal... Args>
void call_animalVoice()
{
(animalVoice<Args>(), ...);
}
template <Animal... Args>
void call_animalVoice(integer_sequence<Animal, Args...>)
{
// (animalVoice<Args>(), ...);
call_animalVoice<Args...>();
}
with call:
call_animalVoice(all_animals)
or maybe std::tuple
constexpr auto all_animals = std::tuple<
std::integral_constant<Animal, DOG>,
std::integral_constant<Animal, CAT>
>{};
and
std::apply([](auto... animals){ (animalVoice<decltype(animals){}()>(), ...);
}, all_animals);
If you allow enumerating from 0 incrementaly then integer_sequence would work:
#include <iostream>
#include <utility>
using namespace std;
enum Animal {
DOG = 0,
CAT,
NUM_ANIMALS
};
template <Animal A>
void animalVoice();
template <>
void animalVoice<DOG>() { cout << "Bau" << endl; }
template <>
void animalVoice<CAT>() { cout << "Meow" << endl; }
template <size_t... Args>
void call_animalVoice()
{
(animalVoice<static_cast<Animal>(Args)>(), ...);
}
template <size_t... Args>
void call_animalVoice(integer_sequence<size_t, Args...>)
{
call_animalVoice<Args...>();
}
int main()
{
call_animalVoice(make_integer_sequence<size_t, NUM_ANIMALS>{});
}
Live Demo on Wandbox
Related
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;
}
Partial specialization for member functions template arguments is possible? I'm not sure, but it is worth a try.
This works just fine (http://coliru.stacked-crooked.com/a/795e953af7537ab6):
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <typename TClass, void(TClass::*t_func)()>
void function()
{
TClass p;
(p.*t_func)();
}
template <typename TClass, void(TClass::*t_func)(), typename TClass2, void(TClass2::*t_func2)(), typename ...Rest>
void function()
{
function<TClass, t_func>();
function<TClass2, t_func2, Rest...>();
}
int main()
{
function<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
}
Output:
Bar()
Bar2()
The next sample also works (http://coliru.stacked-crooked.com/a/e8fe14dde6932f4c):
#include <iostream>
struct Foo { Foo() { std::cout << "Foo()" << std::endl; } };
struct Foo2 { Foo2() { std::cout << "Foo2()" << std::endl; } };
template <typename... Args>
struct Impl;
template <typename TClass, typename ...Rest>
struct Impl<TClass, Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){ std::cout << "EmptyImpl" << std::endl; }
};
template <typename ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Foo, Foo2>();
}
Output:
Foo()
Foo2()
EmptyImpl
But if I want to combine these two things above:
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <typename... Args>
struct Impl;
template <typename TClass, void(TClass::*t_func)(), typename ...Rest>
struct Impl<TClass, decltype(t_func), Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){}
};
template <typename ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
}
it will be a compiler error:
main.cpp: In function 'int main()':
main.cpp:36:59: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... Args> struct Factory'
auto f = Factory<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
main.cpp:36:59: note: expected a type, got '&Foo::Bar'
main.cpp:36:59: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... Args> struct Factory'
main.cpp:36:59: note: expected a type, got '&Foo2::Bar2'
Any idea? What did I miss? :)
consider using additional wrapper for calling member functions
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <class TClass>
using FType = void(TClass::*)();
template<class TClass, FType<TClass> t_func>
class Caller
{
public:
Caller()
{
TClass p;
(p.*t_func)();
}
};
template <typename... Args>
struct Impl;
template <class TClass, typename ...Rest>
struct Impl<TClass, Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){}
};
template <class ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Caller<Foo, &Foo::Bar>, Caller<Foo2, &Foo2::Bar2> >();
}
I would like to have a function, that counts a value down to zero. in addition, i would like to call some code which class is passed as a template parameter.
but this code doesn't work. please can someone help me?
thanks a lot.
The error message is:
"function template partial specialization 'foo<0, T>' is not allowed"
class Hello_World
{
public:
void hello(size_t number){
cout << "hello " << number << endl;
}
};
template<size_t SIZE, class T>
void foo()
{
T t;
t.hello(SIZE);
foo<SIZE-1, Hello_World>();
}
template<class T>
void foo<0,T>()
{
cout << "end." << endl;
}
int main()
{
foo<4,Hello_World>();
}
You can't partially specialize template functions. Wrap it in a class:
template <size_t SZ, typename T >
struct foo_impl
{
static void call()
{
T().hello(SZ);
foo_impl<SZ-1, T>::call();
}
};
template < typename T >
struct foo_impl<0,T>
{
// you get the idea...
};
template <size_t SZ, typename T >
void foo() { foo_impl<SZ,T>::call(); }
You cannot partially specialize a function template. However, you can partially specialize a functor (that basically acts like a function):
#include <iostream>
template<size_t SIZE, class T>
struct foo {
void operator()(){ foo<SIZE-1, T>()(); }
};
template<class T>
struct foo<0,T> {
void operator()(){ std::cout << "end." <<std::endl; }
};
int main(){
foo<3,int>()();
}
Can I use variadic templates without using the template parameters as function parameters?
When I use them, it compiles:
#include <iostream>
using namespace std;
template<class First>
void print(First first)
{
cout << 1 << endl;
}
template<class First, class ... Rest>
void print(First first, Rest ...rest)
{
cout << 1 << endl;
print<Rest...>(rest...);
}
int main()
{
print<int,int,int>(1,2,3);
}
But when I don't use them, it doesn't compile and complains about an ambiguity:
#include <iostream>
using namespace std;
template<class First>
void print()
{
cout << 1 << endl;
}
template<class First, class ... Rest>
void print()
{
cout << 1 << endl;
print<Rest...>();
}
int main()
{
print<int,int,int>();
}
Unfortunately the classes I want to give as template parameters are not instantiable (they have static functions that are called inside of the template function).
Is there a way to do this?
template<class First> // 1 template parameter
void print()
{
cout << 1 << endl;
}
#if 0
template<class First, class ... Rest> // >=1 template parameters -- ambiguity!
void print()
{
cout << 1 << endl;
print<Rest...>();
}
#endif
template<class First, class Second, class ... Rest> // >=2 template parameters
void print()
{
cout << 1 << endl;
print<Second, Rest...>();
}
Make it a type.
template <typename... Ts>
struct print_impl;
template <typename T>
struct print_impl<T> {
static void run() {
std::cout << 1 << "\n";
}
};
template <typename T, typename... Ts>
struct print_impl<T, Ts...> {
static void run() {
std::cout << 1 << "\n";
print_impl<Ts...>::run();
}
};
template <typename... Ts>
void print() {
print_impl<Ts...>::run();
}
int main() {
print<int, int, int>();
return 0;
}
template <class T, bool flag>
class A
{
//...
void f()
{
std::cout << "false" << std::endl;
}
//...
};
template<class T>
void A<T, true>::f<T, true>()
{
std::cout << "true" << std::endl;
}
The code above is wrong and don't compile, but you get the idea of what I'm going to do. So how should I do that?
You can't specialize just one method of a class. Usually you can solve that with a template nested class on the same T.
template <class T, bool flag>
class A
{
//...
template <class Q, bool flag>
class F_Helper
{
void operator()()
{
std::cout << "false" << std::endl;
}
};
template <class Q>
class F_Helper<Q, true>
{
void operator()()
{
std::cout << "true" << std::endl;
}
};
F_Helper<T> f;
//...
};
Obviously a bit more boilerplate is needed if you do need access to the enclosing class' this pointer.
Contrary to what the other answers say, you can specialize a member function of a class template. But you need to provide all template arguments
template<>
void A<int, true>::f()
{
std::cout << "true" << std::endl;
}
What you try is not valid:
template<typename T>
void A<T, true>::f()
{
std::cout << "true" << std::endl;
}
Partially specializing a member of a class template for particular arguments of that class template is not valid, so that means "define the member function 'f' of a partial specialization of A for <T, true>". Because there is no such partial specialization, the compiler will error out.
If you cannot provide all arguments, you can overload f as follows
template <class T, bool flag>
class A
{
template<typename, bool> struct params { };
void f()
{
f(params<T, flags>());
}
template<typename U>
void f(params<U, true>) {
std::cout << "true" << std::endl;
}
template<typename U, bool flag1>
void f(params<U, flag1>) {
std::cout << "dunno" << std::endl;
}
};
You can specialize whole template class - Ideone link
#include <iostream>
template <class T, bool flag>
class A
{
//...
void f()
{
std::cout << "false" << std::endl;
}
//...
};
template<class T>
class A<T, true>
{
//...
void f()
{
std::cout << "true" << std::endl;
}
//...
};
You need to specialize the whole class:
#include <iostream>
template <class T, bool flag>
class A
{
public:
void f()
{
std::cout << "false" << std::endl;
}
};
template<class T>
class A<T,true>
{
public:
void f()
{
std::cout << "true" << std::endl;
}
};
void main()
{
A<int, false> a;
a.f();
A<int, true> b;
b.f();
}