What's the correct way to write a specialization for an empty argument variadic template. Take bellow code as an example:
#include <iostream>
#include <memory>
#include <tuple>
#include <functional>
#include <cassert>
using namespace std;
struct message {
int type;
};
struct X: message {
int payload;
X(): message{1} {
}
};
struct Y: message {
int payload;
Y(): message{2} {
}
};
struct Z: message {
int payload;
Z(): message{3} {
}
};
template<typename T>
constexpr int message_type = -1;
template<>
constexpr int message_type<X> = 1;
template<>
constexpr int message_type<Y> = 2;
template<>
constexpr int message_type<Z> = 3;
struct M {
int payload;
M(int payload): payload{ payload } {
}
};
template<typename P, typename T1, typename... Ts>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg, function<int(unique_ptr<T1>&)> fn1, function<int(unique_ptr<Ts>&)>... fn) {
if (msg->type == message_type<T1>) {
unique_ptr<T1> m(static_cast<T1*>(msg.release()));
auto result = fn1(m);
return {result, make_unique<M>(m->payload)};
} else {
return helper<void, Ts...>(msg, fn...);
}
}
template<typename P>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg) {
assert(false);
return {0, unique_ptr<M>()};
}
template<typename... Ts>
tuple<int, unique_ptr<M>> dispatch_msg(unique_ptr<message> &msg, function<int(unique_ptr<Ts>&)> ...fn) {
return helper<void, Ts...>(msg, fn...);
}
int main() {
auto *real_message = new Z;
real_message->payload = 101;
unique_ptr<message> msg(real_message);
auto [result, m] = dispatch_msg<X, Y, Z>(msg, [](auto &x) {
return x->payload + 1;
}, [](auto &y) {
return y->payload + 2;
}, [](auto &z) {
return z->payload + 3;
});
cout << result << '\n' << m->payload << endl;
return 0;
}
The helper function takes variadic template arguments. If it checked all given type arguments and failed. e.g. run to the empty arguments. I want to assert and stop the process.
The current code works but I'm wondering is there any straightforward way to write a specialization.
I simplified the core requirements into the code below:
template<typename T, typename... Ts>
void func(int val, T arg, Ts... args) {
if (condition_hold<T>(val)) {
return;
} else {
return func<Ts...>(val, args...);
}
}
template<>
void func(int val) {
assert(false);
}
int main() {
func<int, double, float>(100);
return 0;
}
Basically the func is checking against every given type whether a condition hold for the input val. If all check failed I want to do something, like the assert here. So I wrote a specialization takes empty argument, but this can't compile.
In C++17, you don't need to split parameter packs into head and tail in most cases. Thanks to fold expressions, many operations on packs become much easier.
// Some generic predicate.
template <typename T>
bool condition_hold(T) {
return true;
}
// Make this whatever you want.
void do_something_with(int);
template<typename... Ts>
auto func(int val, Ts... args) {
// Fold expression checks whether the condition is true for all
// elements of the parameter pack.
// Will be true if the parameter pack is empty.
if ((condition_hold(args) && ...))
do_something_with(val);
}
int main() {
// Ts type parameters are deduced to <float, float>.
func(100, 1.f, 2.f);
return 0;
}
To check whether the pack was empty and handle this case specially, you can do:
template<typename... Ts>
auto func(int val, Ts... args) {
if constexpr (sizeof...(Ts) == 0) {
// handle empty pack
}
else {
// handle non-empty pack
}
}
Your specialization couldn't have worked because func<> needs to take at least one parameter. A specialization such as
template<typename T>
void func<T>(int val);
Wouldn't be valid either, because it wold be a partial specialization which is only allowed for classes.
However, if the base template only takes a pack, we can fully specialize it:
template<typename... Ts>
void func(int val, Ts... args);
template<>
void func<>(int val);
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);
}
In bellow sample code I'm trying to check if function arguments are pointers or not with std::is_pointer
it works fine if there is only one parameter, but how to make it work with more parameters, such as in parameter pack?
#include <type_traits>
#include <iostream>
class Test
{
public:
template<typename... Params>
void f(Params... params);
template<typename T, typename... Params>
auto sum(T arg, Params... params)
{
return arg + sum(params...);
}
template<typename T>
auto sum(T arg)
{
return arg;
}
int member = 1;
};
template<typename... Params>
void Test::f(Params... params)
{
// ERROR: too many template arguments for std::is_pointer
if constexpr (std::is_pointer_v<Params...>)
member += sum(*params...);
else
member += sum(params...);
std::cout << member;
}
int main()
{
Test ts;
// both fail
ts.f(1, 2);
ts.f(&ts.member, &ts.member);
// is that even possible?
ts.f(&ts.member, 2);
return 0;
}
I guess if parameters are not either all pointers or all not pointers then we have additional issue, but let's just assume all arguments are either pointers or not.
then what about if arguments are mix of pointers and non pointers anyway?
You can use a fold expression:
#include <iostream>
#include <type_traits>
template <typename... Ts>
void test(Ts... ts) {
if constexpr ((std::is_pointer_v<Ts> && ...)) {
std::cout << "yes\n";
} else {
std::cout << "no\n";
}
}
int main() {
test(new int, new char, new int);
test(new int, new char, new int, 2);
}
The output of the program:
yes
no
Be careful with your function template signature though - I would advise using Ts&&... ts instead of Ts... ts, because of how const char[]s are treated. With my original example, test(new int, new char, new int, "hello"); will yield a yes output, but with Ts&&... ts, it will yield no.
For anyone using C++11/14, you can use the following solution.
// helper struct that checks the list
template<int N, typename... Args>
struct is_all_pointer_helper;
// N > 1, checks the head and recursively checks the tail
template<int N, typename Arg, typename... Args>
struct is_all_pointer_helper<N, Arg, Args...> {
static constexpr bool value =
std::is_pointer<Arg>::value &&
is_all_pointer_helper<N-1, Args...>::value;
};
// N == 1, checks the head (end of recursion)
template<typename Arg, typename... Args>
struct is_all_pointer_helper<1, Arg, Args...> {
static constexpr bool value = std::is_pointer<Arg>::value;
};
// N == 0, define your result for the empty list
template<> struct is_all_pointer_helper<0> {
static constexpr bool value = false;
};
// user interface
template<typename... Args>
struct is_all_pointer : is_all_pointer_helper<sizeof...(Args), Args...> {};
// C++14 only
template<typename... Args>
constexpr bool is_all_pointer_v = is_all_pointer<Args...>::value;
class Foo {};
int main()
{
cout << std::boolalpha << is_all_pointer<int*, char*, Foo*>::value << endl;
cout << std::boolalpha << is_all_pointer_v<int*, char, Foo*> << endl; //C++14
cout << std::boolalpha << is_all_pointer<>::value << endl;
}
Output:
true
false
false
The problem can be simplified (and the program made to work) by moving the detection of whether a param is a pointer into the variadic template function sum.
example:
#include <type_traits>
#include <iostream>
class Test
{
public:
template<typename... Params>
void f(Params... params)
{
member += sum(params...);
std::cout << member << '\n';
}
template<typename... Params>
auto sum(Params... params)
{
auto contents = [](auto param)
{
using ParamType = std::decay_t<decltype(param)>;
if constexpr (std::is_pointer_v<ParamType>)
return *param;
else
return param;
};
return (contents(params) + ...);
}
int member = 1;
};
int main()
{
Test ts;
// both fail
ts.f(1, 2);
ts.f(&ts.member, &ts.member);
// is that even possible?
ts.f(&ts.member, 2);
return 0;
}
Expected output:
4
12
26
https://godbolt.org/z/y57-TA
I have a function with a non-type template parameter of type int, like so:
template <int N>
int foo() { /*...*/ }
I would like to unit test this function for all values of N from 0 to 32. I have a function int expected(int n) that takes the same N value and returns the expected value. Effectively, I want:
if (foo<0>() != expected(0)) { /* fail... */ }
if (foo<1>() != expected(1)) { /* fail... */ }
if (foo<2>() != expected(2)) { /* fail... */ }
// 30 more lines
I don't want to write out all 33 test cases by hand, and I can't easily use a runtime loop because N is compile time.
How can I get the compiler to generate the test cases for me in a simple way, without BOOST_PP_REPEAT-style tricks or code generation, in C++11?
You can write a recursive function template with full specialization to perform the test. e.g.
template <int N>
void test() {
test<N-1>();
if (foo<N>() != expected(N)) { /* fail... */ }
}
template <>
void test<-1>() {
// do nothing
}
and run it like
test<32>();
In c++14 you can do something like this
#include <type_traits>
template <int beg, int end> struct static_for {
template <typename Fn> void operator()(Fn const& fn) const {
if (beg < end) {
fn(std::integral_constant<int, beg>());
static_for<beg + 1, end>()(fn);
}
}
};
template <int n> struct static_for<n, n> {
template <typename Fn> void operator()(Fn const& fn) const {}
};
template <int N> int foo() { /*...*/
return N;
}
int main() {
static_for<0, 32>()([&](auto i) {
if (foo<i>() != i) { /* fail... */
}
});
return 0;
}
Here's a method:
template<int N>
void f();
template<int... N>
void g(std::index_sequence<N...>)
{
(f<N>(), ...);
}
Which can be called like so:
g(std::make_index_sequence<33>());
Edit:
Here's version that actually checks if the tests completed successfully:
template<int N>
int f();
int expected(int n);
template<int... N>
bool g(std::index_sequence<N...>)
{
return ((f<N>() == expected(N)) && ...);
}
Which is used like:
g(std::make_index_sequence<33>()); // true if all tests are sucessful, false otherwise
A possible C++14 solution, that "simulate" the C++17 template-folding and interrupt the f<N> != expected(N) at first failure
template <int N>
void f ();
template <int ... Is>
void g (std::integer_sequence<int, Is...>)
{
using unused = int[];
bool ret { false };
(void)unused { 0, (ret ? 0 : (ret = (f<Is>() != expected(Is)), 0))... };
}
callable as follows
g(std::make_integer_sequence<33>());
For a C++11 solution, you need a substitute for std::make_integer_sequence/std::integer_sequence that are available only from C++14.
I have a template that requires that I pass it a functor as a type parameter in order to perform some calculations. I would like to specialize this functor based on another function that I want to use to actually perform the calculations. Basically, I want to do this (which is not legal, I'm redefining the functor):
template<typename T, int (*func)(int)>
struct Functor
{
T val;
int operator()(int x) { return func(2); }
};
template<typename T, int (*func)(int, int)>
struct Functor
{
T val;
int operator()(int y) { return func(y, 2); }
};
Component<Functor<calculationFunction1>> comp1;
Component<Functor<calculationFunction2>> comp2;
auto result1 = comp1.Compute();
auto result2 = comp2.Compute();
I've tried using partial specialization to get this to work as well, but that doesn't seem to be legal, either. I'm not sure if it's possible to get what I want, since the two functions have differing signatures. What's the best way to achieve what I'm trying to do here?
How about:
template<typename T, typename SOME_FUNC_TYPE, SOME_FUNC_TYPE func >
struct Functor {};
typedef int (*SingleArgFunc)(int);
typedef int (*DoubleArgFunc)(int,int);
template<typename T, SingleArgFunc func>
struct Functor<T, SingleArgFunc, func>
{
T val;
int operator()(int x) { return func(2); }
};
template<typename T, DoubleArgFunc func>
struct Functor<T, DoubleArgFunc, func>
{
T val;
int operator()(int y) { return func(y, 2); }
};
int calculationFunction1 (int) { return 0; }
int calculationFunction2 (int, int) { return 0; }
template <typename FUNCTOR>
struct Component
{
int Compute (void) { return FUNCTOR()(0); }
};
Component<Functor<int, decltype(&calculationFunction1), calculationFunction1>> comp1;
Component<Functor<int, decltype(&calculationFunction2), calculationFunction2>> comp2;
auto result1 = comp1.Compute();
auto result2 = comp2.Compute();
Say I have a template declaration like this:
template <class A, class B, class C = A (&)(B)>
How would I make it so that I could have a variable amount of objects of type C? Doing class C ...c = x won't work because variadic template arguments can't have default values. So this is what I've tried:
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (&type)(B);
};
template <class F, class B, typename helper<F(B)>::type ... C>
void f(C ...c) { // error
}
But up to the last part I get error messages. I don't think I'm doing this right. What am I doing wrong here?
I think you can use the following approach. First, some machinery for type traits. This allows you to determine if the types in an argument pack are homogeneous (I guess you want all functions to have the same signature):
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
Then, some more type traits to figure out the signature of a generic function:
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
And finally, this is how you would define your variadic function template:
template <typename... F>
void foo(F&&... f)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
// ...
}
Here is a short test:
int fxn1(double) { }
int fxn2(double) { }
int fxn3(string) { }
int main()
{
foo(fxn1, fxn2); // OK
foo(fxn1, fxn2, fxn3); // ERROR! not homogeneous signatures
return 0;
}
Finally, if you need an inspiration on what to do once you have that argument pack, you can check out a small library I wrote (from which part of the machinery used in this answer is taken). An easy way to call all the functions in the argument pack F... f is the following (credits to #MarkGlisse):
initializer_list<int>{(f(forward<ArgType>(arg)), 0)...};
You can easily wrap that in a macro (just see Mark's answer to the link I posted).
Here is a complete, compilable program:
#include <iostream>
#include <type_traits>
using namespace std;
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
template <typename F>
void foo(F&& f)
{
cout << f(42) << endl;
}
template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
cout << f(42) << endl;
foo(fs...);
}
int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }
int main()
{
foo(fxn1, fxn2, fxn3); // OK
// foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures
return 0;
}
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (*type)(B);
};
template<class F, class B>
void f()
{
}
template <class F, class B, typename... C>
void f(typename helper<F(B)>::type x, C... c)
{
std::cout << x(B(10)) << '\n';
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int main()
{
f<int,int>(identity,half,square,cube);
}
Here's a modified version that can deduce types:
template<class F, class B>
void f(F(*x)(B))
{
x(B());
}
template <class F, class B, typename... C>
void f(F(*x)(B), C... c)
{
f(x);
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int string_to_int(std::string) { return 42; }
int main()
{
f(identity,half,square,cube);
// f(identity,half,string_to_int);
}