Consider the following code:
#include <iostream>
enum class E
{
A,
B
};
template<E e> int f();
template<> int f<E::A>(){ return 1; }
template<> int f<E::B>(){ return 2; }
int main()
{
for( const E i : {E::A, E::B} )
{
std::cout << f<i>() << "\n";
}
}
This fails to compile, because i is not initialised with a constant expression. Is it possible make this idea of a code work?
This is very related: Why isn't a for-loop a compile-time expression?.
i in your loop is not a constant expression. However, by stealing from this answer one can make your code call f<i> inside the loop. It is not directly what you asked for because the proposed solution is for size_t index based loops instead of iterators, but it does call f<i> for all values of the enum:
#include <iostream>
#include <utility>
// your code
enum class E
{
A,
B
};
template<E e> int f();
template<> int f<E::A>(){ return 1; }
template<> int f<E::B>(){ return 2; }
// https://stackoverflow.com/a/47563100/4117728
template<std::size_t N>
struct num { static const constexpr auto value = N; };
template <class F, std::size_t... Is>
void for_(F func, std::index_sequence<Is...>)
{
using expander = int[];
(void)expander{0, ((void)func(num<Is>{}), 0)...};
}
template <std::size_t N, typename F>
void for_(F func)
{
for_(func, std::make_index_sequence<N>());
}
// emulate constexpr for (size_t i=0;i<2;++i) f<i>();
int main()
{
for_<2>([&] (auto i) {
std::cout << f<static_cast<E>(decltype(i)::value)>();
});
}
Output:
12
Probably there is a simpler solution for your actual problem. The answer to your literal question is: No. You cannot call f<i> when i is not a compile time constant. For detailed explanation I refer you to the above mentioned q&a.
The compiler is not able to deduce i in the call to f<i>(). This is because compilation happens before runtime, and the value of i is only available during runtime. You can work around this by adding a translator.
#include <iostream>
enum class E
{
A,
B
};
template<E e> int f();
template<> int f<E::A>(){ return 1; }
template<> int f<E::B>(){ return 2; }
int bar(E e)
{
int retval = 0;
switch(e)
{
case E::A:
{
return f<E::A>();
break;
}
case E::B:
{
return f<E::B>();
break;
}
default:
{
break;
}
}
return retval;
}
int main()
{
for( const E i : {E::A, E::B} )
{
std::cout << bar(i) << "\n";
}
return 0;
}
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);
}
//parameter pack sum example
constexpr int sum(int N= 0)
{
return N;
}
template<typename ...Args>
constexpr int sum(int first, int second, Args ...N)
{
return first + second + sum(N...);
}
int main()
{
std::cout << sum<int>(1,6,3);
}
Is it possible to make this sum at compile time with std::initializer_list<int> how can i iterate recursive through this.
sum with std::initializer_list might be done the following way in C++11:
template <typename It>
constexpr int sum(It it, It end)
{
return it == end ? 0 : (*it + sum(it + 1, end));
}
constexpr int sum(std::initializer_list<int> ini)
{
return sum(ini.begin(), ini.end());
}
static_assert(sum({1, 2, 3, 4, 5})== 15, "!");
Demo
C++14 allows loop in constexpr function allowing to get rid of recursion:
constexpr int sum(std::initializer_list<int> ini)
{
int res = 0;
for (int e : ini) {
res += e;
}
return res;
}
And in C++20, std::accumulate is marked as constexpr, allowing
constexpr int sum(std::initializer_list<int> ini)
{
return accumulate(ini.begin(), ini.end(), 0);
}
Since C++20, you can use std::reduce as it is marked constexpr:
#include <initializer_list>
#include <numeric>
constexpr int sum(std::initializer_list<int> init) {
return std::reduce(init.begin(), init.end());
}
Here is a solution doing the same more purely without initializer list and constexpr. Works with with gcc-4.4 which has partial C++11 support:
#include <iostream>
template<int N, int ...Args>
struct SumImpl
{
enum { RESULT = N + SumImpl<Args...>::RESULT };
};
template<>
struct SumImpl<0>
{
enum { RESULT = 0 };
};
template<int ...Args>
struct Sum
{
enum { RESULT = SumImpl<Args..., 0>::RESULT };
};
int main()
{
std::cout << Sum<1,6,0,3,23>::RESULT << "\n";
}
I want a function pointer that points to a function that takes as argument a class with a template parameter (see main). I believe I'm close to the right syntax, but I receive the compilation error: "a template declaration cannot appear at block scope".
#include <iostream>
#include <array>
template<int N>
class NumberHolder
{
public:
NumberHolder();
int x_;
};
template<int N>
NumberHolder<N>::NumberHolder() : x_(N) {}
template<int N, int M>
void add(NumberHolder<N>& nh)
{
nh.x_ += M;
}
template<int N, int M>
void mult(NumberHolder<N>& nh)
{
nh.x_ *= M;
}
int main()
{
NumberHolder<3> nh;
//using f_ptr = void(*)(NumberHolder<3>&); // Compiles
template<int N> using f_ptr = void(*)(NumberHolder<N>&); // Doesn't compile
std::array<f_ptr, 2> operations;
operations[0] = &add<3, 41>;
operations[1] = &mult<3, 8>;
for (int i = 0; i < operations.size(); ++i)
{
operations[i](nh);
}
std::cout << nh.x_ << std::endl;
return 0;
}
You have to move your template alias outside of local scope:
template <int N> using f_ptr = void (*)(NumberHolder<N>&);
int main()
{
const std::array<f_ptr<3>, 2> operations {&add<3, 41>, &mult<3, 8>};
NumberHolder<3> nh;
for(const auto& operation : operations) {
operation(nh);
}
std::cout << nh.x_ << std::endl;
return 0;
}
Live example.
I've this situation:
class A {
...
};
class B {
public:
B(A x) { .... }
}
std::array<A, some_constant_value> init;
std::array<B, some_constant_value> arr = {
init[0],
init[1],
init[2],
...... ,
init[some_constant_value-1]
};
Is there, by any chance, a better syntax than this to avoid typing all the elements down? ( And that won't require meddling in the off-chance that some_constant_value will change? )
I have this code lying around. I think it's what you want:
template<unsigned... Indices>
struct indices {
using next = indices<Indices..., sizeof...(Indices)>;
};
template<unsigned N>
struct build_indices {
using type = typename build_indices<N-1>::type::next;
};
template<>
struct build_indices<0> {
using type = indices<>;
};
namespace impl {
template<typename To, typename From, unsigned... Is>
std::array<To, sizeof...(Is)>
array_convert_impl(std::array<From, sizeof...(Is)> const& from, indices<Is...>) {
return std::array<To, sizeof...(Is)>{{ from[Is]... }};
}
} // namespace impl
template<typename To, typename From, unsigned N>
std::array<To, N>
array_convert(std::array<From, N> const& from) {
return impl::array_convert_impl<To>(from, typename build_indices<N>::type());
}
Then you can do:
std::array<B, some_constant_value> arr = array_convert<B>(init);
An alternative solution provided by the Standard Library is:
std::array<B, some_constant_value>
arr((std::copy(init.begin(),init.end(),(&arr)->begin()),arr));
Note that the argument of the constructor is enclosed by ((...)), so that it
is correctly parsed as a comma-expression rather than as two arguments.
This solution relies upon the fact that B is implicitly constructible from
A. A short solution that will also work if the converting constructor is
made explicit is:
auto lamb =
[&init]() -> B { static size_t i = 0; return B(init[i++]); };
std::array<B, some_constant_value>
arr((std::generate((&arr)->begin(),(&arr)->end(),lamb),arr));
The following test program, built with GCC 4.7.2, clang 3.2 and Intel C++ 13.1.1,
(options -g -O0 -Wall -std=c++11) illustrates both solutions:
#include <iostream>
#include <array>
#include <algorithm>
struct A
{
int _i = 42;
};
struct B
{
B(A x)
: _i(x._i){}
int _i;
};
struct C
{
explicit C(A x)
: _i(x._i){}
int _i;
};
using namespace std;
int main()
{
array<A, 10> init;
array<B, 10> arr((copy(init.begin(),init.end(),(&arr)->begin()),arr));
cout << "arr contains..." << endl;
for (size_t i = 0; i < arr.size(); ++i) {
cout << arr[i]._i << endl;
}
auto lamb =
[&init]() -> C { static size_t i = 0; return C(init[i++]); };
array<C, 10> brr((generate((&brr)->begin(),(&brr)->end(),lamb),brr));
cout << "brr contains..." << endl;
for (size_t i = 0; i < brr.size(); ++i) {
cout << brr[i]._i << endl;
}
return 0;
}
let's say I have this:
struct myStruct {
int A;
int B;
}
Is it possible to set a specific member via a template parameter like this?
void setTo10<?? member>(myStruct& obj) {
obj.member = 10;
}
//usage:
setTo10<"member A">(obj);
I know it's possible with a macro but how about a template?
thanks
Something like this?
struct myStruct {
int A;
int B;
};
template <typename T, typename V>
void set(T& t, V T::*f, V v)
{ t.*f = v; }
int main()
{
myStruct m;
set(m, &myStruct::A, 10);
std::cout << m.A << '\n';
}
This solution allows to select a member via a compile-time index (which could be computed via another compile-time expression):
struct myStruct {
int A;
int B;
};
template <int n1, int n2>
struct SetOnEqual
{
static void set(int& var, int val)
{} // default: do nothing
};
template<int n>
struct SetOnEqual<n, n>
{
static void set(int& var, int val)
{
var = val;
}
};
template <int n>
void setTo10(myStruct& s)
{
SetOnEqual<n,0>::set(s.A, 10);
SetOnEqual<n,1>::set(s.B, 10);
}
Then the following code
#include <stdio.h>
int main()
{
myStruct s;
s.A = s.B = 0;
setTo10<0>(s); // sets s.A
printf("s=(%d,%d)\n", s.A, s.B);
setTo10<1>(s); // sets s.B
printf("s=(%d,%d)\n", s.A, s.B);
return 0;
}
gives the output
s=(10,0)
s=(10,10)