I am trying to understand the C++11 feature called "variadic". Look at this simple code:
#include <iostream>
using namespace std;
template<typename T, typename... Args>
T adder(T first, Args... args) {
return first + adder(args...);
}
int main() {
int c = adder(1,8,4);
cout << c << endl;
cout << "Hello World!" << endl;
return 0;
}
Readig the c++ primer book I have understood that they work in recursive way and I also see that in the recursive call the args... part is passed.
I am using MinGW 5 and QtCreator to test this. Look
Ok, to fix the Too few arguments I could call adder(first, args...) but now the recursion is not proper and the program crashes. What to do? I cannot understand how to do this.
Looking online I've found an example like this
template <typename T, typename... Rest>
double sum(T t, Rest... rest) {
return t + sum(rest...);
}
It's basically the same. Do I have to put an explicit (non template) return type?
You need the "stop-recursion-case" (do not know the correct name now; UPDATE: it's called "base-case", thanks Quentin) with just one argument when the template function is unfolding.
#include <iostream>
template<typename T>
T adder(T first) {
return first;
}
template<typename T, typename... Args>
T adder(T first, Args... args) {
return first + adder(args...);
}
int main() {
const int c = adder(1, 8, 4);
std::cout << c << '\n';
return 0;
}
With C++17 fold expression you can do it with a single function.
You don't need the "stop-recursion-case".
template<typename... Args>
auto sum(Args... args)
{
return (args + ...);
}
Example usage, all print 42
std::cout << sum(42) << '\n';
std::cout << sum(11, 31.0) << '\n'; // different types
std::cout << sum(3, 4, 5, 6, 7, 8, 9) << '\n';
using namespace std::string_literals;
std::cout << sum("4"s, "2"s) << '\n'; // concatenating strings
Your recursion unfolds like this:
adder(1,8,4)
-> adder<int,int,int>(1,8,4)
-> 1 + adder<int,int>(8,4)
-> 1 + 8 + adder<int>(4)
-> 1 + 8 + 4 + adder<>()
so Args... is getting shorter every time, and eventually is empty.
But your declaration
template<typename T, typename... Args>
T adder(T first, Args... args);
can't be called with zero arguments, it always needs at least one (first).
So, the options are either
add an overload which does take zero arguments, like
int adder() { return 0; }
add an overload taking exactly one argument, which doesn't try to continue the recursion:
template <typename T>
T adder(T t) { return t; }
either one will fix the bug, but the second is much better, because it works for any T, and the first will only add things that are implicitly convertible from int{0}.
This pattern - the general recursive case plus the terminal case which stops recursion - was common before variadic templates were introduced (we previously used LISP-like recursive lists for this sort of thing, which naturally use recursion like this).
The newer style enabled by variadic templates takes advantage of pack expansion to avoid recursion entirely. See for example the summation example using std::apply
The answer from #christian-g is correct. However, I would like you to notice that this function can be generalised to any return type with auto keyword.
template<typename T1, typename T2>
auto adder(const T1& t1, const T2& t2) {
return t1 + t2;
}
template<typename T1, typename... T2>
auto adder(const T1& t1, const T2&... t2) {
return t1 + adder(t2...);
}
Now you can use it for different types
auto sum1 = adder(1, 2, 3); // sum1 is int
auto sum2 = adder(1, 2., 3); // sum2 is double
There was an issue I have run against once with concatenating values to the string result, but it was solved in type deduction from char array to std::string
A variadic template parameter like Args allows the case with sizeof...(Args)=0, which returns the number of variadic template arguments. Using C++11 you need to define a case that is valid for no variadic templates given like
template<typename _T>
_T adder(_T first) { return first; }
However considering different types like double and int it is not always meaningful to return _T, mayber you want to change it to auto or declytpe.
Additionally this problem is solved in C++17 if you are intreseted.
template<typename ...Args>
int sum(Args&&... args) {
return (args + ... + (1 * 2));
}
Related
#include <iostream>
using namespace std;
template <class T, class... Other>
auto sum(T& first, Other... other)
{
T mas[] = { other... };
cout << "size: " << sizeof...(other) << endl;
//T *f = other...;
for (int m : mas)
first += m;
return first;
}
int main()
{
int summa = 0;
sum(summa, 1, 2, 3, 4, 5, 6, 7);
cout << "sum: " << summa << endl;
return 0;
}
There is a short piece of code that outputs the following:
size: 7
sum: 28
The question is very simple and quick to get the same answer:
How do I access element by element each variable accounting parameter other? I tried to create a pointer, but it constantly complains, in short, I don’t know how it looks syntactically.
I will make a reservation right away that I am not interested in how to decompose the elements into an array, I myself know how exactly I should refer to each element exactly other.
More precisely, how to expand the parameter package without recursion and not decomposing the elements into an array?
How to expand the parameter package without recursion?
You have since C++17-fold expression for this needs.
Using it, your function will simply be
template <class T, class... Other>
auto sum(T& first, const Other&... other)
{
first = (other + ... + first);
return first;
}
or without the redundant variable summa may be:
#include <type_traits> // std::common_type_t
template <class... Other>
constexpr auto sum(const Other&... other) /* noexcept */
{
return (other + ... + std::common_type_t<Other...>{});
}
See a demo
How do I access element by element each variable accounting parameter other?
You can apply fold expression along with an immediately invoking lambda function as follows:
template <typename ReType, typename... Other>
auto do_something_with_args(ReType& ret, Other&&... other)
{
([&ret](auto /* const& */ arg) {
// do something with each arg and ret
ret += arg; // example
std::cout << arg << '\n';
}(std::forward<Other>(other)), ...);
return ret;
}
See a demo
If you do not have access to C++17, then there are tweaks/ alternatives, which have been mentioned in the following posts:
What is a good alternative to this C++17 fold expression in C++14?
How to call a function on all variadic template args?
How about this solution?
template <class T, class... Other>
auto sum(T& first, Other... other)
{
std::apply([&first](auto &&... i){(..., (first += i)); }, std::make_tuple(std::forward<Other>(other)...));
return first;
}
In an answer to another question I posted, Jack Harwood shared a nice solution to detect empty variadic parameter packs using concepts. The example problem is to compute the number of parameter pack arguments using recursion. I reproduce his solution below.
template <typename... Args>
concept NonVoidArgs = sizeof...(Args) > 0;
template <typename... Args>
concept VoidArgs = sizeof...(Args) == 0;
template <VoidArgs...>
constexpr int NumArguments() {
return 0;
}
template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments() {
return 1 + NumArguments<RemainingArgs...>();
}
Example:
int main() {
std::cout << NumArguments<int>() << std::endl; // 1
std::cout << NumArguments() << std::endl; // 0
std::cout << NumArguments<float, int, double, char>() << std::endl; // 4
return 0;
}
I think that this is a better solution than using class templates to specialize function templates. However, I'm not sure why it works. The template function
template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments()
seems to require at least two template arguments. There needs to be a FirstArg and then at least 1 RemainingArgs. Why does the compiler call this overload(?) when there is only one template argument? Does this behavior create any problems with this solution?
The concepts themselves are correct but the problem is that the example uses them incorrectly and is itself faulty. In the given code the concept is imposed on an argument basis instead of the entire parameter pack.
Your current version
template<typename FirstArg, NonVoidArgs... RemainingArgs>
constexpr int NumArguments() {
return 1 + NumArguments<RemainingArgs...>();
}
is actually equivalent to a requires clause and a fold expression
template<typename FirstArg, typename... RemainingArgs>
int NumArguments() requires (NonVoidArgs<RemainingArgs> && ...) {
return 1 + NumArguments<RemainingArgs...>();
}
This actually means you are defining a function that must have an argument FirstArg and might have an additional parameter pack of arbitrary size RemainingArgs (including zero!). Each of these arguments - if present - is then checked independently if it fulfills the NonVoidArgs concept which of course is always true. This means the function basically degenerates to
template<typename FirstArg, typename... RemainingArgs>
int NumArguments() {
return 1 + NumArguments<RemainingArgs...>();
}
That being said it is actually not even necessary for the parameter pack to be NonVoidArgs: Try it here!
The correct way to impose restrictions not only on the data type of a single template argument but the entire parameter pack would actually be a requires clause as follows:
template<typename FirstArg, typename... RemainingArgs>
int NumArguments() requires NonVoidArgs<RemainingArgs...> {
return 1 + NumArguments<RemainingArgs...>();
}
As expected this would not work: Try it here! I guess the person who has written the code was just lucky it actually works as they did not enforce the concepts correctly. The basic idea behind the concept is flawed.
following main code works fine
string hello = "Hello ";
string world = "templates!";
cout << "var template add: ";
cout << setprecision(2) <<
var_template_add(5, 4, 5.5, 4.0);
for following template generator code and variadic func
template <typename T>
auto add(T a, T b) {
return a + b;
}
template <typename T, typename... Rest>
auto var_template_add(T first, T second, Rest... others) {
return first + second + add (others...);
}
But if added two more string args, like this
var_template_add(5, 4, 5.5, 4.0, hello, world);
is caught by compiler error saying "no matching overloaded function found".
Again,
string hello = "Hello ";
string world = "templates!";
cout << "strings add result: " << setprecision(2) << add(hello, world) << endl;
could work if i write template function "add" like below:
template <typename T1, typename T2>
auto add(T1 a, T2 b) {
return a + b;
}
My question is, how could i make the line
var_template_add(5, 4, 5.5, 4.0, hello, world);
work without writing another add function like just above?!
please note i could use tuple to pass this values but for now, i just want to keep away. any thoughts/improvements?
Adding std::string to integral values will not work unless you choose to make your function explicitly convert to string, such as using a std::stringstream or std::to_string.
If you want this to behave correctly with stringizing behavior, you will need to change it to do some form of explicitly string building.
However, you can at least make your current var_template_add work with any number of arguments, since the current definition requires 4 arguments or it will not work. This will allow the var_template_add(hello, world) example to work.
In C++11 this can be done by using some template recursion. This doesn't require adding any new functions per-se -- just renaming an existing one and altering one.
The idea is to recursively call the var_template_add until you end up with 2 arguments, and then just add the two together:
// rename'add' to 'var_template_add'. Use this as recursive base-case.
template <typename T, typename U>
auto var_template_add(T first, U second)
-> decltype(first + second)
{
return first + second;
}
// adds first argument and delegates 'second' and 'others...' to the next 'var_template_add'
template <typename T, typename U, typename... Rest>
auto var_template_add(T first, U second, Rest... others)
-> decltype(first + var_template_add(second, others...))
{
return first + var_template_add(second, others...);
}
For 2 arguments, it will call the first overload. For 3 or more arguments, it will call the second, which will recursively call into the next var_template_add, until eventually calling into the first.
Note: This answer is because the question is tagged C++11 -- but please be aware that your use of auto return types without a trailing return type is actually C++14 and not C++11.
If you have C++17, you can do this even easier using variadic fold expressions:
template <typename T, typename U, typename...Rest>
auto var_template_add(T first, U second, Rest...others)
{
return first + second + (... + others);
}
Edit:
Since OP updated the tags to include c++14 and c++17, you can achieve the stringizing add behavior quite easily using either to_string or stringstream and a fold expression. For this, I do recommend a different function though -- since appending string sequences is semantically quite a different operation from "adding" values.
The best approach would probably be to use std::stringstream, something like:
template <typename...Args>
std::string variadic_add_str(Args&&...args)
{
auto stream = std::string_stream{};
stream << (... << std::forward<Args>(args));
return stream.str();
}
The only way for the current call to work is for var_template_add to return a single type, so it would need to be a string.
Instead, you could write the cout inside the function, so then you only need:
template <typename T, typename... Rest>
auto var_template_add(T first, T second, Rest... others) {
cout << setprecision(2) << (first + second) << " ";
if constexpr (sizeof...(others)) var_template_add(others...);
}
Here's a demo.
Note that there is no if constexpr pre c++17, so in that case, having an extra overload as base case is a good option.
I would like to have a general function 'request' which could accept a tuple of any number of arguments. I want the 'request' function to dispatch the call to a number of other functions, depending on the number of arguments (of course the interface of the functions must match).
I wrote this code, but it only works if I call function of one type inside the 'request'. As soon as I uncomment the dispatching mechanism (else -> dispatch to fun5) everything stops compiling.
The problem is that the body of function 'request', created for the case of dispatching to function with two parameters, must compile, and then there is a function with 5 arguments inside it, to which the tuple of 2 arguments cannot be applied. And vice versa. Classic problem with templates. I know that I could somehow apply SFINAE concept to this problem, but I somehow don't know how (I am not as strong in MPL programming).
#include <iostream>
#include <experimental/tuple>
enum class type { v2, v5 };
void fun2(int i1, int i2)
{
std::cout << "fun2 called, i1 = " << i1 << ", i2 = " << i2 << std::endl;
}
void fun5(bool b1, float f1, int i, char c, bool b2)
{
std::cout << "fun5 called with: " << std::boolalpha << b1 << ", " << f1 << ", " << i << ", " << c << ", " << b2 << std::endl;
}
template <typename F, typename... T>
void dispatch(F f, T... args)
{
std::experimental::apply(f, args...);
}
template <typename... T>
void request(type t, T... args)
{
if (t == type::v2)
dispatch(fun2, args...);
// else
// dispatch(fun5, args...);
}
int main()
{
auto v2 = std::make_tuple(1,1);
request(type::v2, v2);
// auto v5 = std::make_tuple(true, 1.5f, 3, 'c', false);
// request(type::v5, v5);
}
How can I make this work? What kind of dispatching mechanism I need here to make this work?
Instead of using an enumeration to select what to do, I suggest you use tags and tag structures instead. Then you can simply select the right dispatch function using simple function overloading.
Perhaps something like
namespace type
{
struct v2_tag {};
struct v5_tag {};
v2_tag v2;
v5_tag v5;
}
template<typename... T>
void request(type::v2_tag, T... args)
{
dispatch(fun2, args...);
}
template<typename... T>
void request(type::v5_tag, T... args)
{
dispatch(fun5, args...);
}
The rest of the code stays the same.
An alternative to tag dispatch (which I highly recommend as per #Some programmer dude) would be to create your own function object that accepts a type as a non-type template argument so that we can take advantage of constexpr if:
template<type t>
struct request
{
template<class... T>
void operator()(T... args) const
{
if constexpr(t == type::v2)
dispatch(fun2, args...);
else
dispatch(fun5, args...);
}
};
The downside is that you have to construct one to make your call:
auto v2 = std::make_tuple(1, 1);
request<type::v2>()(v2);
auto v5 = std::make_tuple(true, 1.5f, 3, 'c', false);
request<type::v5>()(v5);
Demo
A variation on this approach is to instead have a static apply function in your request class like so:
template<type t>
struct request{
template<class... T>
static void apply(T... args){/*..*/}
}
And then a call to it would look like this instead (no funky empty braces):
request<type::v2>::apply(v2);
Demo2
I have the following problem. Say you want to write a generic function that can take a lambda expression. I understand that if the parameter is of type std::function, then I could not only use lambdas, but also functions and even pointers to functions. So at a first step, I did the following:
void print(std::function<void(int, int)> fn) {
fn(1,2);
}
int main() {
print([](int i, int j) { std::cout << j <<','<<i<<'\n'; });
return 0;
}
Now the problem is that I want to make this function generic, meaning that I don't want the lambda expression to have only two parameters.
So I tried changing the signature of the print function to something more generic like:
template <class function_type>
void print(function_type fn);
But now the problem is that the function takes ANY object and I'm not ok with that.
But the main problem is that, I have no idea how many parameters the object fn can accept.
So in a way I'm looking for a compile time way to determine how many arguments fn has, and if possible to change the type of fn to std::function. And then, given that I know the number of parameters that fn accepts, is there a generic way to pack an arbitrary number of parameters to be passed to fn? I don't even know if this is possible within C++11. What I mean is that given the number of arguments, is there a way to pack parameters to pass to fn? So that if there are two arguments, then I would call
fn(arg1, arg2);
if there are three:
fn(arg1, arg2, arg3);
and so on.
Thank you all for your insight.
aa
The following snippets might be useful.
This gives the number of arguments that a std::function takes
template <typename Signature>
struct count_args;
template <typename Ret, typename... Args>
struct count_args<std::function<Ret(Args...)>> {
static constexpr size_t value = sizeof...(Args);
};
For example the following code compiles (clang 3.2, gcc 4.7.2 and icc 13.1.0)
static_assert(count_args<std::function<void() >>::value == 0, "Ops!");
static_assert(count_args<std::function<void(int) >>::value == 1, "Ops!");
static_assert(count_args<std::function<void(int, int)>>::value == 2, "Ops!");
As far as I understand, you want to call the function object passing the correct number of arguments, right? Then for each argument we need to provide a value which is convertible to its type. A solution with this generality is very hard (or even impossible). Hence, I'll present two alternatives.
1 Each argument is a value initialized object of its type. (This is what ecatmur suggested.)
template <typename Ret, typename... Args>
Ret call(const std::function<Ret(Args...)>& f) {
return f(Args{}...); // for the intel compiler replace {} with ()
}
2 A fixed value is given and all the arguments are implicitly initialized from this value:
template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<sizeof...(Args) == sizeof...(Vals), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val&, const Vals&... vals) {
return f(vals...);
}
template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<(sizeof...(Args) > sizeof...(Vals)), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val& val, const Vals&... vals) {
return call(f, val, val, vals...);
}
The three overloads are unambiguous and can be used as the following examples show:
{
std::function<char()> f = []() -> char {
std::cout << "f() ";
return 'A';
};
std::cout << call(f) << std::endl; // calls f()
std::cout << call(f, 0) << std::endl; // calls f()
}
{
std::function<char(int)> f = [](int i) -> char {
std::cout << "f(" << i << ") ";
return 'B';
};
std::cout << call(f) << std::endl; // calls f(0)
std::cout << call(f, 1) << std::endl; // calls f(1)
}
{
std::function<char(int, int)> f = [](int i, int j) -> char {
std::cout << "f(" << i << "," << j << ") ";
return 'C';
};
std::cout << call(f) << std::endl; // calls f(0, 0)
std::cout << call(f, 2) << std::endl; // calls f(2, 2)
}
Yes you can pack as many parameters to fn as you wish using variadic templates.
template <class function_type, class... Args>
void print(function_type fn, Args... args)
{
//Call fn with args
fn(std::forward<Args>(args...));
}
To find out how many args there are in the parameter pack, you can use sizeof...(args).
To determine the signature of a callable, you can use the solution from Inferring the call signature of a lambda or arbitrary callable for "make_function". You can then package the callable into a std::function, or create a tag and use parameter inference:
template<typename T> struct tag {};
template<typename F, typename... Args>
void print_impl(F &&fn, tag<void(Args...)>) {
fn(Args{}...);
}
template<typename F>
void print(F &&fn) {
print_impl(std::forward<F>(fn), tag<get_signature<F>>{});
}
Note this uses value-initialised arguments; if you want anything more complex you can build a std::tuple<Args...> and pass that along, invoking it per "unpacking" a tuple to call a matching function pointer.