Syntax for overloaded template functions with lambda function arguments - c++

I need help with the syntax for the following C++ (17) code:
#include <iostream>
struct st_a {
int var;
};
struct st_b {
double var;
};
void func(void(cb)(st_a)) {
st_a a;
a.var = 3;
cb(a);
}
void func(void(cb)(st_b)) {
st_b b;
b.var = 4;
cb(b);
}
class test {
public:
test() {
func([](st_a arg) { std::cout << arg.var; });
func([this](st_a arg) { my_func_a(arg); });
func([this](st_b arg) { my_func_b(arg); });
}
void my_func_a(st_a arg) {
std::cout << arg.var;
}
void my_func_b(st_b arg) {
std::cout << arg.var;
}
};
int main(void)
{
test t;
}
Unsurprisingly the compiler gives me
error: no matching function for call to ‘func(test::test()::<lambda(st_a)>)’
I attempted to rectify it using template functions, i.e.,
template<typename F>
void func(F cb) {
st_a a;
a.var = 3;
cb(a);
}
template<typename F>
void func(F cb) {
st_b b;
b.var = 4;
cb(b);
}
But this results in
error: redefinition of ‘template<class F> void func(F)’
...which is no surprise.
My question is how can I change the template parameters to specify the function argument?
Follow up from analyzing replies
I forgot to mention that I'm chasing nanoseconds, so std::function is not an option.
The assembly output from Yksisarvinen's and max66's solutions is identical, branch-free, and very compact (the whole program compiles into 9 assembly instructions). The std::function assembly on the other hand contains page upon page of branches and function calls, which invalidates this approach from an execution speed prespective.
From a code readability perspective, perhaps std::function is the best option. In my opinion, the second best alternative is the one max66 presented, i.e
template <typename F> auto func (F cb) -> decltype(cb(std::declval<st_a>()), void()) { ...; }
this is also the best approach for portability (C++11) when compared to Yksisarvinen's solution.
Thank you for your help.

The other answers explain the core issue with capturing lambda, but you can solve the problem without std:function by using some template metaprogramming with std::enable_if.
template<typename F, std::enable_if_t<std::is_invocable_v<F, st_a>, bool> = true>
void func(F cb) {
st_a a;
a.var = 3;
cb(a);
}
template<typename F, std::enable_if_t<std::is_invocable_v<F, st_b>, bool> = true>
void func(F cb) {
st_b b;
b.var = 4;
cb(b);
}
With definitions as such, compiler will only generate first func if F can be invoked with argument of type st_a and second func if the argument can be invoked with argument of type st_b. It will probably break if both could be true at the same time (e.g. if you introduce inheritance between st_a and st_b).
See it online

The problem is that the lambdas defined here
func([this](st_a arg) { my_func_a(arg); });
func([this](st_b arg) { my_func_b(arg); });
have captures. You can think of a lambda as a class that implements operator(). Lambdas with captures have members in that class.
If you have a lambda with no captures, the compiler provides an implicit conversion to a function pointer, because this is essentially what it is.
If you have a lambda with captures, the compiler can not provide an implicit conversion because you would not be able to fit all these captures into a single pointer.
(If you are interested in lambdas in C++, I'd recommend looking at Jason Turners "Weekly C++" episodes from which many are about lambdas. This one talks about what lambdas are.)
The C++ standard library provides std::function which is some type-erasure magic that, honestly, I don't fully understand. (I remember watching a C++ Weekly episode about that, but I can't recall properly what it does.)
Anyways, by taking a std::function you get a small overhead and the standard library will just make everything work.

Another way (almost equivalent to the std::is_invocable_v answer from Yksisarvinen, but working also before C++17) could be the following
template <typename F>
auto func (F cb) -> decltype( cb(std::declval<st_a>()), void() )
{
st_a a{3};
cb(a);
}
template <typename F>
auto func (F cb) -> decltype( cb(std::declval<st_b>()), void() )
{
st_b b{4};
cb(b);
}

You are passing a lambda function to something that expects a function pointer, so the type doesn't match. I would suggest changing func to accept a std::function as callback, so that you can pass a lambda to it
#include <functional>
void func(std::function<void(st_a)> cb) {
st_a a;
a.var = 3;
cb(a);
}
void func(std::function<void(st_b)> cb) {
st_b b;
b.var = 4;
cb(b);
}

Related

Member function passed as std::function to template, binding all params

I have started building the permission management library,
the basic idea is that you have some sort of configuration read from a file and based on that you can execute a functional object which will be wrapping "allow" and "restrict" functions.
The code so far is divided into few parts
I have a permission manager which says if given "std::string" is able to be executed or not:
class PermissionManager {
public:
virtual bool canAccess(std::string resource) {return true;};
};
Next, I have the actual wrapper on the function:
template <typename FuncT>
class PermissionFunction {
private:
FuncT m_restrict;
FuncT m_allow;
PermissionManager *m_pManager;
std::string m_resource;
public:
PermissionFunction(const PermissionFunction&) = delete;
PermissionFunction& operator=(const PermissionFunction&) = delete;
PermissionFunction(FuncT r, FuncT a, PermissionManager *man, std::string res)
: m_restrict(r), m_allow(a), m_pManager(man), m_resource(res){
}
template<typename ...ARG>
typename std::result_of<FuncT(ARG&&...)>::type operator()(ARG&&... args){
if(m_pManager->canAccess(m_resource)){
return m_allow(std::forward<ARG>(args)...);
} else {
return m_restrict(std::forward<ARG>(args)...);
}
}
};
So, the usage is something like:
PermissionManager tpm{};
std::function<void(int)> testRestrict = [](int a){std::cout << "Restrict" << std::endl;};
std::function<void(int)> testAllow = [](int a){std::cout << "Allow" << std::endl;};
PermissionFunction<decltype(testRestrict)> testPerm(testRestrict, testAllow, &tpm, "hi");
for(int i = 0; i <10; i++){
testPerm(i);
}
It works really nice for the non member std::functions, however when I want to define it with a member function it gets very messy:
class test {
public:
void testato(int i){
std::cout << i << std::endl;
}
PermissionManager perm{};
PermissionFunction<std::function<void(int)>>
permf{
std::bind(&test::testato, this, std::placeholders::_1),
std::bind(&test::testato, this, std::placeholders::_1),
&perm, "hi"};
};
I am wondering if there is any way to shorten up the usage for the member variable types, I was thinking about using the template for that as well but I am not sure how to use std bind with veriadic template parameters and it has to work for any function type.
The goal would be to have the function declaration similar to the one with the std::functions in the example given, so that I can define the member object in this maner:
some_template<decltype(member_f)>
wrapper_member{member_f, member_f, &tpm, "resource"}
Where member_f is an actual member function of a class. Ideally the type would be deduced but I think it would also be acceptable to repeat it in such manner:
some_template<return_t(args_t)>
wrapper_member{member_f, member_f, &tpm, "resource"}
C++20 introduces std::bind_front which binds arguments only to the leading parameters, and so doesn't require the use of placeholder objects. It could be used to make your code more concise.
PermissionFunction<std::function<void(int)>> permf{
std::bind_front(&test::testato, this),
std::bind_front(&test::testato, this),
&perm, "hi"};
A possible C++17 implementation:
#include <tuple>
#include <utility>
template <typename F, typename... Xs>
auto bind_front(F&& f, Xs&&... xs)
{
return [
f = std::forward<F>(f),
xs = std::make_tuple(std::forward<Xs>(xs)...)](auto&&... ys) -> decltype(auto)
{
return std::apply(
f,
std::tuple_cat(xs, std::forward_as_tuple(std::forward<decltype(ys)>(ys)...)));
};
}

Neat way to parametrize function template with generic function pointer

Consider following case: I have
int bar1();
double bar2();
I want:
foo<bar1>(); // calls bar1, then uses its result.
foo<bar2>(); // calls bar2, then uses its result.
Naive way to write template foo() is to use additional parameter:
template <typename T, T (*f)()> void foo () {
// call f, do something with result
}
This works, but I need to do ugly syntax:
foo<decltype(bar1()), bar1>(); // calls bar1, then uses its result
I want to write something pretty, like above, just foo<bar1>.
P.S. Please do not recommend to accept argument at runtime. I need compile time parametrization with function pointer only.
P.S. Sorry forget to mention: I am looking for C++14 solution. C++17 appreciated and I upvoted answer with C++17 solution, but project now builds with C++14 and I can not change it in nearest future.
In order to get
foo<bar1>();
You need template<auto> from C++17. That would look like
int bar1() { return 1; }
double bar2() { return 2.0; }
template<auto function> void foo() { std::cout << function() << "\n"; }
int main()
{
foo<bar1>();
foo<bar2>();
}
Which outputs
1
2
Live Example
Before C++17 you have to specify the type as there is no auto deduction of the type of a non type template parameters.
So, I'll try to give the best possible answer that I'm aware of in 14. Basically a good approach (IMHO) to this problem is to "lift" the function pointer into a lambda. This allows you to write foo in the much more idiomatic way of accepting a callable:
template <class F>
void foo(F f);
You still get optimal performance, because the type of the lambda is unique, and so it gets inlined. You can more easily use foo with other things though. So now we have to turn our function pointer into a lambda that is hardcoded to call it. The best we can on that front is drawn from this question: Function to Lambda.
template <class T>
struct makeLambdaHelper;
template <class R, class ... Args>
struct makeLambdaHelper<R(*)(Args...)>
{
template <void(*F)(Args...)>
static auto make() {
return [] (Args ... args) {
return F(std::forward<Args>(args)...);
};
}
};
We use it like this:
auto lam = makeLambdaHelper<decltype(&f)>::make<f>();
To avoid having to mention it twice, we can use a macro:
#define FUNC_TO_LAMBDA(f) makeLambdaHelper<decltype(&f)>::make<f>()
You could then do:
foo(FUNC_TO_LAMBDA(bar1));
Live example: http://coliru.stacked-crooked.com/a/823c6b6432522b8b
I am looking for C++14 solution. C++17 appreciated and I upvoted answer with C++17 solution, but project now builds with C++14 and I can not change it in nearest future.
Unfortunately what you ask works starting from C++17.
If you want use the exactly syntax
foo<bar1>();
I don't thinks it's possible in C++14.
But, if you accept a little different syntax... I know that macros are distilled evil but... if you accept to call foo() as
FOO(bar1)();
you can define the macro
#define FOO(f) foo<decltype(f()), f>
A full working example
#include <iostream>
#define FOO(f) foo<decltype(f()), f>
int bar1 ()
{ std::cout << "bar1()" << std::endl; return 0; }
double bar2 ()
{ std::cout << "bar2()" << std::endl; return 1.0; }
template <typename T, T (*f)()>
void foo ()
{ f(); }
int main()
{
FOO(bar1)(); // print bar1()
FOO(bar2)(); // print bar2()
}
OK, so you asked specifically for bar1 and bar2 to be functions, but if you were willing to relax that constraint and instead allow them to be classes having a static member function that implements the desired behavior you could do it in the following way, which doesn't even require C++11 -
struct bar1 {
static int f() { return 42; }
};
struct bar2 {
static double f() { return 3.14159; }
};
template<typename bar>
void foo()
{
double x = bar::f();
std::cout << x << std::endl;
}
int main(int argc, char* const argv[])
{
foo<bar1>();
foo<bar2>();
}
How about this?
template<typename F>
auto foo(F* f)
{
return f();
}
int bar() { return 1; }
int main()
{
return foo(bar);
}

aliasing a variadic template function

I have a variadic function like :
void test(int){}
template<typename T,typename...Args>
void test(int& sum,T v,Args... args)
{
sum+=v;
test(sum,args...);
}
I want to alias it to something like :
auto sum = test;//error : can not deduce auto from test
int main()
{
int res=0;
test(res,4,7);
std::cout<<res;
}
I tried using std::bind but it doesn't work with variadic functions because it needs placeholders ...
Is it possible to alias a variadic function ?
In C++1y :
#include <iostream>
void test(int){}
template<typename T,typename...Args>
void test(int& sum,T v,Args... args)
{
sum+=v;
test(sum,args...);
}
template<typename T,typename...Args>
decltype(test<T, Args...>)* sum = &(test<T, Args...>);
int main(void)
{
int res = 0;
sum<int, int>(res, 4, 7);
std::cout << res << std::endl;
}
Alternatively wrap it in another variadic function and std::forward the arguments :
template<typename T,typename...Args>
void other(int&sum, T v, Args&&... args)
{
test(sum, std::move(v), std::forward<Args>(args)...);
}
What you are trying is not much different from
void test(int)
{
}
void test(double, int)
{
}
auto a = test;
There is no way for the compiler to detect which overload you want to use.
You can be explicit about which test you want to assign to a by:
auto a = (void(*)(int))test;
If you want to add the variadic template version to the mix, you can use:
template<typename T,typename...Args>
void test(int& sum,T v,Args... args)
{
sum+=v;
test(sum,args...);
}
auto a = test<int, int, int>;
This is not aliasing.auto a = test tries to declare a variable a with the same type as test and make them equal. Since test isn't a single function, but a function template (and on the top of that you can even overload functions), the compiler can't decide on what the type of a should be.
To alias a template, or as a matter of fact any symbol, you can use the using keyword.
using a = test;
Edit: sorry this one only works for types not functions.

Function wrapper that works for all kinds of functors without casting

I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]

How can I iterate over a packed variadic template argument list?

I'm trying to find a method to iterate over an a pack variadic template argument list.
Now as with all iterations, you need some sort of method of knowing how many arguments are in the packed list, and more importantly how to individually get data from a packed argument list.
The general idea is to iterate over the list, store all data of type int into a vector, store all data of type char* into a vector, and store all data of type float, into a vector. During this process there also needs to be a seperate vector that stores individual chars of what order the arguments went in. As an example, when you push_back(a_float), you're also doing a push_back('f') which is simply storing an individual char to know the order of the data. I could also use a std::string here and simply use +=. The vector was just used as an example.
Now the way the thing is designed is the function itself is constructed using a macro, despite the evil intentions, it's required, as this is an experiment. So it's literally impossible to use a recursive call, since the actual implementation that will house all this will be expanded at compile time; and you cannot recruse a macro.
Despite all possible attempts, I'm still stuck at figuring out how to actually do this. So instead I'm using a more convoluted method that involves constructing a type, and passing that type into the varadic template, expanding it inside a vector and then simply iterating that. However I do not want to have to call the function like:
foo(arg(1), arg(2.0f), arg("three");
So the real question is how can I do without such? To give you guys a better understanding of what the code is actually doing, I've pasted the optimistic approach that I'm currently using.
struct any {
void do_i(int e) { INT = e; }
void do_f(float e) { FLOAT = e; }
void do_s(char* e) { STRING = e; }
int INT;
float FLOAT;
char *STRING;
};
template<typename T> struct get { T operator()(const any& t) { return T(); } };
template<> struct get<int> { int operator()(const any& t) { return t.INT; } };
template<> struct get<float> { float operator()(const any& t) { return t.FLOAT; } };
template<> struct get<char*> { char* operator()(const any& t) { return t.STRING; } };
#define def(name) \
template<typename... T> \
auto name (T... argv) -> any { \
std::initializer_list<any> argin = { argv... }; \
std::vector<any> args = argin;
#define get(name,T) get<T>()(args[name])
#define end }
any arg(int a) { any arg; arg.INT = a; return arg; }
any arg(float f) { any arg; arg.FLOAT = f; return arg; }
any arg(char* s) { any arg; arg.STRING = s; return arg; }
I know this is nasty, however it's a pure experiment, and will not be used in production code. It's purely an idea. It could probably be done a better way. But an example of how you would use this system:
def(foo)
int data = get(0, int);
std::cout << data << std::endl;
end
looks a lot like python. it works too, but the only problem is how you call this function.
Heres a quick example:
foo(arg(1000));
I'm required to construct a new any type, which is highly aesthetic, but thats not to say those macros are not either. Aside the point, I just want to the option of doing:
foo(1000);
I know it can be done, I just need some sort of iteration method, or more importantly some std::get method for packed variadic template argument lists. Which I'm sure can be done.
Also to note, I'm well aware that this is not exactly type friendly, as I'm only supporting int,float,char* and thats okay with me. I'm not requiring anything else, and I'll add checks to use type_traits to validate that the arguments passed are indeed the correct ones to produce a compile time error if data is incorrect. This is purely not an issue. I also don't need support for anything other then these POD types.
It would be highly apprecaited if I could get some constructive help, opposed to arguments about my purely illogical and stupid use of macros and POD only types. I'm well aware of how fragile and broken the code is. This is merley an experiment, and I can later rectify issues with non-POD data, and make it more type-safe and useable.
Thanks for your undertstanding, and I'm looking forward to help.
If your inputs are all of the same type, see OMGtechy's great answer.
For mixed-types we can use fold expressions (introduced in c++17) with a callable (in this case, a lambda):
#include <iostream>
template <class ... Ts>
void Foo (Ts && ... inputs)
{
int i = 0;
([&]
{
// Do things in your "loop" lambda
++i;
std::cout << "input " << i << " = " << inputs << std::endl;
} (), ...);
}
int main ()
{
Foo(2, 3, 4u, (int64_t) 9, 'a', 2.3);
}
Live demo
(Thanks to glades for pointing out in the comments that I didn't need to explicitly pass inputs to the lambda. This made it a lot neater.)
If you need return/breaks in your loop, here are some workarounds:
Demo using try/throw. Note that throws can cause tremendous slow down of this function; so only use this option if speed isn't important, or the break/returns are genuinely exceptional.
Demo using variable/if switches.
These latter answers are honestly a code smell, but shows it's general-purpose.
If you want to wrap arguments to any, you can use the following setup. I also made the any class a bit more usable, although it isn't technically an any class.
#include <vector>
#include <iostream>
struct any {
enum type {Int, Float, String};
any(int e) { m_data.INT = e; m_type = Int;}
any(float e) { m_data.FLOAT = e; m_type = Float;}
any(char* e) { m_data.STRING = e; m_type = String;}
type get_type() const { return m_type; }
int get_int() const { return m_data.INT; }
float get_float() const { return m_data.FLOAT; }
char* get_string() const { return m_data.STRING; }
private:
type m_type;
union {
int INT;
float FLOAT;
char *STRING;
} m_data;
};
template <class ...Args>
void foo_imp(const Args&... args)
{
std::vector<any> vec = {args...};
for (unsigned i = 0; i < vec.size(); ++i) {
switch (vec[i].get_type()) {
case any::Int: std::cout << vec[i].get_int() << '\n'; break;
case any::Float: std::cout << vec[i].get_float() << '\n'; break;
case any::String: std::cout << vec[i].get_string() << '\n'; break;
}
}
}
template <class ...Args>
void foo(Args... args)
{
foo_imp(any(args)...); //pass each arg to any constructor, and call foo_imp with resulting any objects
}
int main()
{
char s[] = "Hello";
foo(1, 3.4f, s);
}
It is however possible to write functions to access the nth argument in a variadic template function and to apply a function to each argument, which might be a better way of doing whatever you want to achieve.
Range based for loops are wonderful:
#include <iostream>
#include <any>
template <typename... Things>
void printVariadic(Things... things) {
for(const auto p : {things...}) {
std::cout << p.type().name() << std::endl;
}
}
int main() {
printVariadic(std::any(42), std::any('?'), std::any("C++"));
}
For me, this produces the output:
i
c
PKc
Here's an example without std::any, which might be easier to understand for those not familiar with std::type_info:
#include <iostream>
template <typename... Things>
void printVariadic(Things... things) {
for(const auto p : {things...}) {
std::cout << p << std::endl;
}
}
int main() {
printVariadic(1, 2, 3);
}
As you might expect, this produces:
1
2
3
You can create a container of it by initializing it with your parameter pack between {}. As long as the type of params... is homogeneous or at least convertable to the element type of your container, it will work. (tested with g++ 4.6.1)
#include <array>
template <class... Params>
void f(Params... params) {
std::array<int, sizeof...(params)> list = {params...};
}
This is not how one would typically use Variadic templates, not at all.
Iterations over a variadic pack is not possible, as per the language rules, so you need to turn toward recursion.
class Stock
{
public:
bool isInt(size_t i) { return _indexes.at(i).first == Int; }
int getInt(size_t i) { assert(isInt(i)); return _ints.at(_indexes.at(i).second); }
// push (a)
template <typename... Args>
void push(int i, Args... args) {
_indexes.push_back(std::make_pair(Int, _ints.size()));
_ints.push_back(i);
this->push(args...);
}
// push (b)
template <typename... Args>
void push(float f, Args... args) {
_indexes.push_back(std::make_pair(Float, _floats.size()));
_floats.push_back(f);
this->push(args...);
}
private:
// push (c)
void push() {}
enum Type { Int, Float; };
typedef size_t Index;
std::vector<std::pair<Type,Index>> _indexes;
std::vector<int> _ints;
std::vector<float> _floats;
};
Example (in action), suppose we have Stock stock;:
stock.push(1, 3.2f, 4, 5, 4.2f); is resolved to (a) as the first argument is an int
this->push(args...) is expanded to this->push(3.2f, 4, 5, 4.2f);, which is resolved to (b) as the first argument is a float
this->push(args...) is expanded to this->push(4, 5, 4.2f);, which is resolved to (a) as the first argument is an int
this->push(args...) is expanded to this->push(5, 4.2f);, which is resolved to (a) as the first argument is an int
this->push(args...) is expanded to this->push(4.2f);, which is resolved to (b) as the first argument is a float
this->push(args...) is expanded to this->push();, which is resolved to (c) as there is no argument, thus ending the recursion
Thus:
Adding another type to handle is as simple as adding another overload, changing the first type (for example, std::string const&)
If a completely different type is passed (say Foo), then no overload can be selected, resulting in a compile-time error.
One caveat: Automatic conversion means a double would select overload (b) and a short would select overload (a). If this is not desired, then SFINAE need be introduced which makes the method slightly more complicated (well, their signatures at least), example:
template <typename T, typename... Args>
typename std::enable_if<is_int<T>::value>::type push(T i, Args... args);
Where is_int would be something like:
template <typename T> struct is_int { static bool constexpr value = false; };
template <> struct is_int<int> { static bool constexpr value = true; };
Another alternative, though, would be to consider a variant type. For example:
typedef boost::variant<int, float, std::string> Variant;
It exists already, with all utilities, it can be stored in a vector, copied, etc... and seems really much like what you need, even though it does not use Variadic Templates.
There is no specific feature for it right now but there are some workarounds you can use.
Using initialization list
One workaround uses the fact, that subexpressions of initialization lists are evaluated in order. int a[] = {get1(), get2()} will execute get1 before executing get2. Maybe fold expressions will come handy for similar techniques in the future. To call do() on every argument, you can do something like this:
template <class... Args>
void doSomething(Args... args) {
int x[] = {args.do()...};
}
However, this will only work when do() is returning an int. You can use the comma operator to support operations which do not return a proper value.
template <class... Args>
void doSomething(Args... args) {
int x[] = {(args.do(), 0)...};
}
To do more complex things, you can put them in another function:
template <class Arg>
void process(Arg arg, int &someOtherData) {
// You can do something with arg here.
}
template <class... Args>
void doSomething(Args... args) {
int someOtherData;
int x[] = {(process(args, someOtherData), 0)...};
}
Note that with generic lambdas (C++14), you can define a function to do this boilerplate for you.
template <class F, class... Args>
void do_for(F f, Args... args) {
int x[] = {(f(args), 0)...};
}
template <class... Args>
void doSomething(Args... args) {
do_for([&](auto arg) {
// You can do something with arg here.
}, args...);
}
Using recursion
Another possibility is to use recursion. Here is a small example that defines a similar function do_for as above.
template <class F, class First, class... Rest>
void do_for(F f, First first, Rest... rest) {
f(first);
do_for(f, rest...);
}
template <class F>
void do_for(F f) {
// Parameter pack is empty.
}
template <class... Args>
void doSomething(Args... args) {
do_for([&](auto arg) {
// You can do something with arg here.
}, args...);
}
You can't iterate, but you can recurse over the list. Check the printf() example on wikipedia: http://en.wikipedia.org/wiki/C++0x#Variadic_templates
You can use multiple variadic templates, this is a bit messy, but it works and is easy to understand.
You simply have a function with the variadic template like so:
template <typename ...ArgsType >
void function(ArgsType... Args){
helperFunction(Args...);
}
And a helper function like so:
void helperFunction() {}
template <typename T, typename ...ArgsType >
void helperFunction(T t, ArgsType... Args) {
//do what you want with t
function(Args...);
}
Now when you call "function" the "helperFunction" will be called and isolate the first passed parameter from the rest, this variable can b used to call another function (or something). Then "function" will be called again and again until there are no more variables left. Note you might have to declare helperClass before "function".
The final code will look like this:
void helperFunction();
template <typename T, typename ...ArgsType >
void helperFunction(T t, ArgsType... Args);
template <typename ...ArgsType >
void function(ArgsType... Args){
helperFunction(Args...);
}
void helperFunction() {}
template <typename T, typename ...ArgsType >
void helperFunction(T t, ArgsType... Args) {
//do what you want with t
function(Args...);
}
The code is not tested.
#include <iostream>
template <typename Fun>
void iteratePack(const Fun&) {}
template <typename Fun, typename Arg, typename ... Args>
void iteratePack(const Fun &fun, Arg &&arg, Args&& ... args)
{
fun(std::forward<Arg>(arg));
iteratePack(fun, std::forward<Args>(args)...);
}
template <typename ... Args>
void test(const Args& ... args)
{
iteratePack([&](auto &arg)
{
std::cout << arg << std::endl;
},
args...);
}
int main()
{
test(20, "hello", 40);
return 0;
}
Output:
20
hello
40