Neat way to parametrize function template with generic function pointer - c++

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);
}

Related

Syntax for overloaded template functions with lambda function arguments

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);
}

How to template Varaidic as return type in template?

I'm stuck with variadic template problem.
Contexte
On one hand, I use a library whose functions look like
template<class ...Cols>
void doForVars(Cols&... args) {
...
}
And on the other hand I have a lot of structs
struct Foo {
int id;
std::string name;
double length;
}
struct Bar {
int id;
double someProperty;
double someOther;
}
I have for each of them to use a specialized template
template<>
void doSomething(Foo& foo) {
//boilerplate
doForVars( foo.id, foo.name, foo.length);
}
template<>
void doSomething(Bar& bar) {
//boilerplate
doForVars( bar.id, bar.someProperty, bar.someOther);
}
Problem and expectations
As I get more than 50 types like Foo and Bar with 10 to 30 fields, there a lot of boilerplate to copy and paste.
It's error-prone and such a violation of DRY that I can stand for it :)
So, I'm searching for to create a template for a function listFields(T& t) that just list fields of record T and whose return value is acceptable for doForVars(Cols...&cols).
template<typename T>
void doSomething(T& t) {
//boilerplate
doForVars(listFields(t));
}
But I don't succeed to write this template returnint a variadic type.
template<typename T, ?>
<I don't know> listFields(T& t);
such as I could just write
template<>
<I don't know> listFields(Foo& foo) {
return <I don't know>( foo.id, foo.name, foo.length);
}
template<>
<I don't know> listFields(Bar& bar) {
return <I don't know>( bar.id, bar.someProperty, bar.someOther);
}
variadic are shown as input, but how to use them for output ?
Thanks by advance.
EDIT
Thank you for your answers I'm reading. As I wrote, I get a lot of record to describe and use ([SCOS 2000 MIB records types])1
The library I use for variadic is this jewel https://github.com/d99kris/rapidcsv
I use it to parse some tabulation separated value files and map each row to my records. Pretty smooth.
Valid for C++17.
What you want might get quite hard and I do not think there is a generic solution apart form using macros.
The first part is actually easy, you can use std::tie and simply return tuples.
auto listFields(Foo& foo) {
return std::tie( foo.id, foo.name, foo.length);
}
I am generally against using template functions and full specialization together. Overloads can do most of the job already. Is there a reason for using them?
Thanks to auto return type and class template argument deduction, there is no need to write any types. I do not think there is a better solution, in C++ it is not possible to return multiple object through the return statement.
Now, about calling those library functions.
If doForVars is the only one you need to call, then the cleanest solution is probably based on this answer:
template<typename T>
void call_doForVars(T& obj){
std::apply([](auto &&... args) { doForVars(args...); }, listFields(obj));
}
int main(){
Foo foo{1,"Quimby",176.5};
call_doForVars(foo);
}
On the other hand, if you have more library functions, you hit a snag that it is AFAIK impossible to pass template function around and you need to pass it into an inner function because the arguments are one of the few places a parameter pack can be expanded. The lambda kinda bypasses this because it can create a function inside an expression.
My best advice so far in this case is to just wrap the previous solution into a macro. You only need to do it once for each library function. (You can do it for listFields too, it will be cleaner).
EDIT
I did find a solution for the generic case after all:
template<typename...Args>
using fnc_t = void(*)(Args&... args);
auto listFields(Foo& foo) {
return std::tie( foo.id, foo.name, foo.length);
}
template<typename...Args>
void call(fnc_t<Args...> f, const std::tuple<Args&...>& t){
std::apply(f, t);
}
int main(){
Foo foo{1,"Quimby",176.5};
call(doForVars, listFields(foo));
}
Was not that hard in the end, it only works with functions for now though.
One downside is that you have to call listFields in every call, which might be handy if your tuples come from other sources too. But if they don't, we can go one step further and get:
template<typename T>
struct helper{
using fnc_t = void;
};
template<typename...Args>
struct helper<std::tuple<Args&...>>{
using fnc_t = void(*)(Args&... args);
};
template<typename T>
using fnc_t2 = typename helper<decltype(listFields(std::declval<T&>()))>::fnc_t;
template<typename T>
void call2(fnc_t2<T> f, T& obj){
std::apply(f, listFields(obj));
}
int main(){
Foo foo{1,"Quimby",176.5};
call2(doForVars, foo);
}
It's more mouthful, but call2 can be hidden anyway and call2(doForVars, foo); is really nice result. :)
Here is a live demo.
You can't return multiple types from a function, even if it's a variadic template. However, you can return a tuple containing all the types that are members of a particular class. Also there seems to be no reason to write a template specialization for each of your Foo, Bar, etc. Instead, you can just add a function to the overload set for every type:
std::tuple<int, std::string, double> listFields(Foo& foo)
{
return {foo.id, foo.name, foo.length};
}
std::tuple<int, double, double> listFields(Bar& bar)
{
return {bar.id, bar.someProperty, bar.someOther};
}
Now since doForVars is a variadic template, you need to unpack the tuple returned form listFields, for which you can use std::apply like this:
template<typename T>
void doSomething(T& t) {
// ...
std::apply([](auto &&... args) { doForVars(args...); }, listFields(t));
}
Here's a demo
As a workaround, you can use std::tuples, as follows
#include <iostream>
#include <string>
#include <tuple>
using namespace std::string_literals;
struct A{
int int_a;
double double_a;
std::tuple<int&, double&> tuplize(){
return {int_a, double_a};
}
};
struct B{
std::string str_b;
bool bool_b;
std::tuple<std::string&, bool&> tuplize(){
return {str_b, bool_b};
}
};
template <class ... Args>
void do_for_vars(Args& ... args){
((std::cout << args << ", "), ...);
std::cout << "\n";
}
template <class ... Args>
void helper(std::tuple<Args...> t){
std::apply(do_for_vars<Args...>, t);
}
int main(){
A a{1, 1.4};
B b{"str"s, true};
helper(a.tuplize());
helper(b.tuplize());
}

Are all lambdas inside templated lambdas also templated lambdas?

Consider this code (which compiles on GCC and MSVC):
int main()
{
auto foo = [](auto p){
typedef decltype(p) p_t;
auto bar = [](){
return static_cast<p_t>(10);
};
return bar();
};
std::cout << foo(0ull) << std::endl;
}
foo() is a templated lambda because it has an auto parameter. But for bar() to know the type p_t, it must somehow be implicitly templated too, which then leads me to the question in the title:
Are all lambdas inside templated lambdas also templated lambdas?
If that's the case, then it seems like the number of templates parameters will grow pretty quickly if I have lots of nested lambdas (not necessarily a bad thing, but it comes as a surprise to me).
I'm not sure if you can actually say that a lambda is templated. The type of lambda with auto template parameter is not a template at all in the sense it does not match to template template parameter:
#include <iostream>
auto foo = [](auto param){};
template <class T>
struct functor_template {
void operator()() const { }
};
template <template <class...> class Foo, class... Ts>
void bar(Foo<Ts...>) {
}
int main() {
//bar(foo); //prog.cc:7:6: note: template argument deduction/substitution failed
bar(functor_template<int>{});
}
The reason for that is quite simple - only thing that is very close to be called template in such lambdas is their operator().
But I think you wanted to ask more if the type of lambda inside the lambda with auto parameter(s) is depended on parameters' types passed to that lambda. The answer is - yes. This can be easily tested:
#include <iostream>
#include <type_traits>
auto foo = [](auto p){
static_cast<void>(p);
typedef decltype(p) p_t;
auto bar = [](){
return static_cast<p_t>(10);
};
return bar;
};
int main() {
static_cast<void>(foo);
std::cout << std::is_same<decltype(foo(int{})), decltype(foo(float{}))>::value << std::endl;
std::cout << std::is_same<decltype(foo(int{})), decltype(foo(int{}))>::value << std::endl;
}
Output:
0
1

Is there in iso or boost function pointer that has the same syntax as std::function

I was wondering if there is a lightweight version of std::function that works only for function pointers but doesnt have horrible :) syntax like regular function pointers.
Aka something like this:
int square(int x)
{
return x*x;
}
//...
function_ptr<int (int)> = square;
Ofc bind and all other fancy stuff std::function supports will fail, but I am ok with that, if I need std::function I will use it.
What you are asking for is for a template to tranform from signature to pointer to function to signature, that is, to add a pointer to the type. That is already done in the standard library:
std::add_pointer<X>::type
But since what you want is the nicer syntax, you can add a template alias:
template <typename T>
using ptr = typename std::add_pointer<T>::type;
Then you can use it directly in your container:
void f(int);
std::vector<ptr<void (int)>> v; // vector of pointers to functions taking `int`
v.push_back(&f);
Depending on the context you want to use this in, it could be as simple as auto and/or decltype:
#include <iostream>
int main()
{
auto f = square;
std::cout << f(5) << std::endl;
// define a type
using F = decltype(&square);
F g = square;
std::cout << g(5) << std::endl;
}
You can write an opaque wrapper if you do not want to use typedef directly. A prototype implementation using variadic templates is as follows. The same technique can be extended to other callable objects such as lambdas.
#include <iostream>
template<typename T>
struct function_ptr {};
template<class R, class... Args>
struct function_ptr<R(Args...)>{
typedef R (*funcType)(Args...);
function_ptr(funcType f) : _f(f) {}
funcType _f;
R operator()(Args... args) { return _f(args...);}
};
int square(int x) {
return x*x;
}
int main() {
function_ptr<int (int)> f = square;
std::cout << f(2) << std::endl;
}

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