I have an api that looks like this:
template<typename... Args>
Widget::Widget(std::string format_str, Args&&... args);
How would you call this method if you have a vector of strings for 'args', i.e. the args length isn't known at compile time?
What would the implementation of a wrapper function look like that would convert this to something like this?
template<typename... Args>
Widget::WrapperWidget(std::string format_str, vector<string>);
The Widget::Widget function actually does not exist, it's only a template. A function is instantiated only after you specify the number and types of the parameters. This must be done in compile time.
Since the length of the vector is only available in runtime, I can think of only this solution:
switch (v.size())
{
case 0: f(fmt); break;
case 1: f(fmt, v[0]); break;
case 2: f(fmt, v[0], v[1]); break;
case 3: f(fmt, v[0], v[1], v[2]); break;
//... etc
}
Note that those f functions are totally different functions in your executable.
Although I'm not sure that I'd like to code above in actual code.
If you wrote the interface than maybe you should extend the interface itself. If not, you may have overloads for this function.
Also reading the parameter names reveals that this is just some kind of pretty printing. You could also make a runtime counterpart to that function and pass as a single argument like this:
string s = format_vector_runtime(fmt, v);
f("%s", s);
where f is still the widget constructor like above and the first parameter is a format string meaning "take the second parameter as is" - may be different for your Widget.
The size of the vector is actually of no concern. I drew up another example of how to process a vector that's supposed to replace stuff in the format string with a variadic function-template approach. You can easily adapt that to work with variadic class-templates. The basic idea is the same:
#include <vector>
#include <string>
#include <iostream>
#include <exception>
using StrCIter = std::string::const_iterator;
void printerHelper(StrCIter& fmtPos, StrCIter fmtEnd, std::vector<std::string>& vec)
{
// if the vector is empty, we simply return without doing anything
// and instead print the next argument
auto vecIter = vec.begin ();
while(vecIter != vec.end () && fmtPos != fmtEnd)
{
if(*fmtPos == '%' && *(fmtPos + 1) == 's')
{
std::cout << *vecIter++;
fmtPos += 2;
continue;
}
std::cout << *fmtPos++;
}
}
template <typename T>
void printerHelper(StrCIter& fmtPos, StrCIter fmtEnd, const T& value)
{
std::cout << value;
fmtPos += 2;
}
void myPrintfHelper(StrCIter pos, StrCIter end)
{
// end of expansion - no more format arguments, just print remaining characters
while(pos != end)
{
if(*pos == '%')
{
throw "More format specifiers than arguments provided!";
}
std::cout << *pos++;
}
}
template <typename Head, typename ... Tail>
void myPrintfHelper(StrCIter pos, StrCIter end, Head&& head, Tail&&... tail)
{
while(pos != end)
{
if(*pos == '%' && *(pos + 1) == 's')
{
printerHelper (pos, end, head);
return myPrintfHelper(pos, end, std::forward<Tail>(tail)...);
}
std::cout << *pos++;
}
}
template <typename ... Args>
void myPrintf(const std::string& format, Args&& ... args)
{
myPrintfHelper (format.begin(), format.end (), std::forward<Args>(args)...);
}
int main()
{
std::vector<std::string> v = {"world", "magic"};
myPrintf("Hello, %s! Welcome to the %s of variadic template %s! This ... is ... C++%s!", "StackOverflow", v, 11);
return 0;
}
Basically, we want to iterate over the formate string and as soon as we hit a format specifier (in our case always represented by %s), we print stuff that is currently the head element resulting from pack expansion. If that element is a vector, we want to iterate further over the format string as long as
we don't hit the end of the format string and
we still have elements in the vector to process
Just like with printf(), superfluous arguments are ignored, if too many format specifiers are found after pack expansion has terminated, we throw an exception.
Note that the idea is inspired by Stroustrups's approach to emulate printf via variadic templates - only my version takes a std::string as format string instead of a const char*.
The good thing is that you can easily make the function more powerful simply by providing another printHelper overload that handles other types that don't provide an operator<<(std::ostream&[, ...]) or cannot be expanded to do so.
All the overload needs to do is handle adjustment of the format-string iterator and print stuff when a format specifier is hit. In my two examples, I do it with a look-ahead of 1 to determine we hit a format specifier, but there are other ways.
Incidentally, the output is:
Hello, StackOverflow! Welcome to the world of variadic template magic! This ... is ... C++11!
Following may help:
#if 1 // Not in C++11
#include <cstdint>
template <std::size_t ...> struct index_sequence {};
template <std::size_t I, std::size_t ...Is>
struct make_index_sequence : make_index_sequence < I - 1, I - 1, Is... > {};
template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
#endif // make_index_sequence
// you may use `std::tostring`
template <typename T> std::string myToString(T&& t);
class Widget
{
public:
Widget(std::string format_str, const std::vector<std::string>& v);
// this will call Widget(std::string, const std::vector<std::string>&)
template<typename... Args>
explicit Widget(std::string format_str, Args&&... args) :
Widget(format_str, std::vector<std::string>{myToString(std::forward<Args>(args))...})
{}
// This will call Widget(format_str, a[0], a[1], .., a[N - 1]) // So the Args&&... version
template <std::size_t N>
Widget(std::string format_str, const std::array<std::string, N>& a) :
Widget(format_str, a, make_index_sequence<N>())
{}
private:
template <std::size_t N, std::size_t...Is>
Widget(std::string format_str, const std::array<std::string, N>& a, const index_sequence<Is...>&) :
Widget(format_str, a[Is]...)
{}
};
Related
I am trying to solve this problem in C++ TMP where in i need to convert one parameter pack types into another, and then convert back the types and also values. The conversion back part is based on a boolean criteria that whether an arg in Args... was transformed or not in the first place.
Basically, i have a pack(Args...). First, i transform this (for each args[i], call a transform function). It works like this:
For each arg in Args..., just create same type in transformed_args... unless it is one of following, in that case do following conversions:
Type In Args...
Type In transformed_Args...
SomeClass
shared_ptr to SomeClass
std::vector of SomeClass
std::vector of shared_ptr to SomeClass
everything else remains the same for ex:
int remains int
std::string remains std::string
I achieve this by template specialization, of course
For the next part, i take transformed_args..., publish a class and a functor. I receive call back on this functor from(C++generated Python using Pybind, not important though). Relevant bits of that class look like this...
template<typename C, typename...transformed_args..., typename... Args>
class SomeTemplateClass
{
MethodWrapper<C,void, Args...> func;
//.....
void operator()(transformed_args... targs)
{
//....
(*func.wrapped_method_inside)(transform_back_magic(targs)...) // this is want i want to achieve.
//transform_back_magic(targs)... is a plaeholder for code that checks if type of args[i]... != type of targs[i]... and then calls a tranform_back specialization on it else just return args[i].val
}
}
targs are in transformed_args... format, but underlying C++ function they are aimed for expects Args...
template<typename... Args, typename... transformed_args, ........whatever else is needed>
transform_back_magic(....)
{
if(Args[i].type != transformed_args[i].types)
tranform_back(targs[i]...);
}
the tranform_back function template logic is specialized for different cases and all logic is in place. But how to invoke that based on this boolean criteria is hitting my TMP knowledge limits. I just got started not many weeks ago.
Here i am listing down what i have created so far.
First of all this is what i need in pseudo code
template<typename C, typename... transformed_args, typename... Args>
class SomeTemplateClass
{
MethodWrapper<C,void, Args...> func;
void operator(transformed_args... targs)
{
**//In pseudo code, this is what i need**
Args... params = CreateArgsInstanceFromTransformedArgs(targs);
(*func.wrapped_method_inside)(params...);
}
}
In my attempt to implement this, so far I have decided on creating a tuple<Args...> object by copying data from targs(with conversions where ever required)
void operator(transformed_args... targs)
{
//....
auto mytup = call1(std::tuple<args...>(), std::make_index_sequence<sizeof...(Args)>,
std::make_tuple(targs...), targs...);
// mytup can be std::tuple<Args...>(transform_back(1st_targs), transform_back(2nd_targs)....). Once available i can write some more logic to extract Args... from this tuple and pass to(*func.wrapped_method_inside)(....)
(*func.wrapped_method_inside)(ArgsExtractorFromTuple(mytup)); // this part is not implemented yet, but i think it should be possible. This is not my primary concern at the moment
}
//call1
template<typename... Args, typename... Targs, std::size_t... N>
auto call1(std::tuple<Args...> tupA, std::index_sequence<N>..., std::tuple<Targs...> tupT, Targs ..)
{
auto booltup = tuple_creator<0>(tupA, tupT, nullptr); // to create a tuple of bools
auto ret1 = std::make_tuple<Args...>(call2(booltup, targs, N)...); // targs and N are expanded together so that i get indirect access to see the corresponding type in Args...
return ret1;
}
// tuple_creator is a recursive function template with sole purpose to create a boolean tuple.
// such that std::get<0>(booltup) = true,
//if tuple_element_t<0,std::tuple<Args...>> and tuple_element_t<0,std::tuple<targs...>> are same types else false
template<size_t I, typename... Targs, typename... Args>
auto tuple_creator(std::tuple<Args...>tupA, std::tuple<Targs...>tupT, std::enable_if_t<I == sizeof...(targs)>*)
{
return std::make_tuple(std::is_same<std::tuple_element_t<I-1, std::tuple<Targs...>>, std::tuple_element_t<I-1, std::tuple<Args...>>>::value);
}
template<size_t I = 0, typename... Targs, typename... Args>
auto tuple_creator(std::tuple<Args...>tupA, std::tuple<Targs...>tupT, std::enable_if_t<I < sizeof...(targs)>*)
{
auto ret1 = tuple_creator<I+1>(tupA, tupT, nullptr);
if(!I)
return ret1;
auto ret2 = std::is_same<std::tuple_element_t<I-1, std::tuple<Targs...>>, std::tuple_element_t<I-1, std::tuple<Args...>>>::value;
return std::tuple_cat(ret1, std::make_tuple(ret2));
}
template<typename TT, typename Tuple>
auto call2(Tuple boolyup, TT t, std::size_t I)
{
auto ret = transform_back<std::get<I>(booltup)>(t); // error: I is not a compile time constant
return ret;
}
transform_back is a template that uses a bool template param and enable_if based specialization to decide whether transform an argument back or not
below are the transform_back specialization for std::vector. Similarly i have others for when T = Class etc and so on
template<bool sameTypes, typename T>
std::enable_if_t<(is_vector<T>::value, is_shared_ptr<typename T::value_type>::value &&
is_class<remove_cvref_t<typename T::value_type_element_type>>::value
&& sameTypes), T>
transform_back(T val) // it was never transfoemd in first place, return as is
{
return val;
}
template<bool sameTypes, typename T>
std::enable_if_t<(is_vector<T>::value, is_shared_ptr<typename T::value_type>::value
&& is_class<remove_cvref_t<typename T::value_type_element_type>>::value
&& !sameTypes),
typename std::vector<typename T::value_type::element_type>>
transform(T val)
{
std::vector<T::value_type::element_type> t;
for(int i = 0 ; i < val.size(); ++i)
{
typename T::value_type::element_type obj = *val[i];
t.push_back(obj);
}
return t;
}
Both these specialization are same and only differ on sameTypes boolean variable
This code currently errors out in call2 method while trying to using
std::get
auto ret = transform_back<std::get<I>(booltup)>(t); // error: I is not a compile time constant
How can you help?
1)What could be the work around to std::get issue here? Just cant figure out a way to fit in std::size_t as template arg here instead of function arg to make it work at compile time.
Other than this:
2)If you can suggest an alternative approach to implement from top level.
Args... params = CreateArgsInstanceFromTransformedArgs(targs);
That would be great. The path i took is not very convincing personally to me.
If I understand correctly, you might do something like:
template <typename> struct Tag{};
std::shared_ptr<SomeClass> transform_to(Tag<std::shared_ptr<SomeClass>>, const SomeClass& s)
{
return std::make_shared<SomeClass>(s);
}
std::vector<std::shared_ptr<SomeClass>> transform_to(Tag<std::vector<std::shared_ptr<SomeClass>>>, const std::vector<SomeClass>& v)
{
std::vector<std::shared_ptr<SomeClass>> res;
res.reserve(v.size());
for (const auto& s : v) {
res.emplace_back(std::make_shared<SomeClass>(s));
}
return res;
}
const SomeClass& transform_to(Tag<SomeClass>, const std::shared_ptr<SomeClass>& s)
{
return *s;
}
std::vector<SomeClass> transform_to(Tag<std::vector<SomeClass>>, const std::vector<std::shared_ptr<SomeClass>>& v)
{
std::vector<SomeClass> res;
res.reserve(v.size());
for (const auto& s : v) {
res.emplace_back(*s);
}
return res;
}
template <typename T>
const T& transform_to(Tag<T>, const T& t) { return t; } // No transformations
And then
std::function<void (Args...)> func;
template <typename ... transformed_args>
void operator () (transformed_args... targs) const
{
func(transform_to(Tag<Args>(), targs)...);
}
Just explaining the use case here to add some context. Consider these three methods in C++ each represented with the function pointer SomeTemplateClass::func:
void foo(vector<shared_ptr<SomeClass>>) // 1
// Args... = vector<shared_ptr<SomeClass>>, Targs... = vector<shared_ptr<SomeClass>>
void foo(vector<SomeClass>) // 2
// Args... = vector<SomeClass>, Targs... = vector<shared_ptr<SomeClass>>
void foo(vector<SomeClass>, vector<shared_ptr<SomeClass>>) // 3
// Args... = vector<SomeClass>, vector<shared_ptr<SomeClass>>, Targs... = vector<shared_ptr<SomeClass>>, vector<shared_ptr<SomeClass>>
One instance each of SomeTemplateClass is exposed to Python via Pybind. I do these transformations so that when foo is called from Python, any arg vector<T>(in C++) is received as vector<shared_ptr<T>> in SomeTemplateClass functor. This helps in to get handle to previously created objects T that i need.
But as you can see from 3 cases for foo, foo(vector<shared_ptr<T>>) does not need to be transformed to and subsequently not need to be transformed back. The case of 'tranform_to'is easily handled with template specialization, but while transforming back, vector<shared_ptr<T>> cant be blindly converted back to vector<T>. So (transform(targs...)) needs an additional logic to transform a particular arg (or targ) only when targ[i]::type != arg[i]::type
Building on Jarod's answer, i rather need something like this where in transform_to method for vector<shared_ptr> is further divided in two possible templates
template<bool wasOriginallyTransformed>
enable_if<!wasOriginallyTransformed, std::vector<std::shared_ptr<SomeClass>> transform_to(Tag<std::vector<SomeClass>>, const std::vector<std::shared_ptr<SomeClass>>& v)
{
return v;
}
template<bool wasOriginallyTransformed>
enable_if<!wasOriginallyTransformed, std::vector<<SomeClass>
transform_to(Tag<std::vector<SomeClass>>, const std::vector<std::shared_ptr<SomeClass>>& v)
{
std::vector<SomeClass> res;
res.reserve(v.size());
for (const auto& s : v) {
res.emplace_back(*s);
}
return res;
}
I am trying to implement a function which accepts a variable number of strings and forwards to a print function, which expects a char pointer and size for every string, interleaved.
Example:
std::string a = "123";
std::string b = "1234";
forward(a, b); // should call doPrint(a.c_str(), a.size(), b.c_str(), b.size())
I thought that the following should be a correct implementation, but even though it compiles the behavior is very surprising to me.
template <class ...Args>
void forward(const Args & ... args) {
doPrint( (args.c_str(), args.size())...);
}
forward(a, b) calls doPrint(3, 4), and not doPrint("123", 3, "1234", 4), as if I had written doPrint((args.size())...). The call to c_str() is ignored completely by the compiler.
I tried g++, clang, and icc with all yielding the same output. What is wrong with (args.c_str(), args.size())...?
Indeed, std::make_tuple(args.c_str(), args.size())... works as expected, but let's say I cannot change doPrint to accept and process tuples.
The comma operator is an expression whose value is the value of the last expression.
For example:
int a = (1, 2, 3, 4, 5, 6);
assert(a == 6);
What you can try instead is using tuples:
doPrint(std::tuple_cat(std::make_tuple(argc.c_str(), args.size())...));
Then doPrint will need to be changed to work with a tuple; it could unpack the tuple back into a parameter pack if desired or just work with the tuple directly.
Example unpacking tuple:
template <class Tuple, std::size_t ... indices>
doPrint(Tuple t, std::integer_sequence<size_t, indices...>)
{
doPrint(std::get<indices>(t)...);
}
template <class Tuple>
doPrint(Tuple t)
{
doPrint(t, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
There could be some problems with ambiguous function names so you may need to change the names of these helper functions, but hopefully this is enough for you to get going.
(args.c_str(), args.size()) is a comma-separated expression, meaning that only the last part (args.size()) will be passed to the function.
It will then repeat this for each parameter, so it will actually call doPrint just with the strings sizes!
You should change doPrint to use tuples instead, otherwise you have to use some crazy template meta-programming stuff.
I'd probably do it this way in order to avoid exposing tuples to the programming interface:
#include <string>
#include <utility>
#include <tuple>
extern void doPrint(...);
namespace detail {
template<std::size_t...Is, class Tuple>
void forward(std::index_sequence<Is...>, Tuple&& tuple)
{
doPrint(std::get<Is>(tuple)...);
}
}
template<class...Strings>
void forward(Strings&&... strings)
{
detail::forward(std::make_index_sequence<sizeof...(Strings) * 2>(),
std::tuple_cat(std::make_tuple(strings.data(), strings.size())...)
);
}
int main()
{
std::string a = "123";
std::string b = "1234";
forward(a, b); // should call doPrint(a.c_str(), a.size(), b.c_str(), b.size())
}
Jason Turner demonstrates a concise way to expand variadic templates using an initializer list in this video:
http://articles.emptycrate.com/2016/05/09/variadic_expansion_wrap_up.html
template< typename ... T >
void do_print(T ... args)
{
(void)std::initializer_list<int> {
(std::cout << args.c_str() << ": "
<< args.size() << "\n", 0)...
};
}
template< typename ... T >
void forward_print(T ... args)
{
do_print(args...);
}
int main(int argc, const char * argv[])
{
std::cout << "Hello, World!\n";
std::string a = "1234";
std::string b = "567";
forward_print(a, b);
return 0;
}
This works with g++ -std=c++11
I have a variable i of type std::size_t and a tuple of type std::tuple. I want to get the i-th element of the tuple. I tried this:
// bindings... is of type const T&...
auto bindings_tuple = std::make_tuple(bindings...);
auto binding = std::tuple_element<i, const T&...>(bindings_tuple);
But I get this compile error saying that the first template argument must be an integral constant expression:
error: non-type template argument of type 'std::size_t' (aka 'unsigned long') is not an integral constant expression
Is it possible to get the i-th element of a tuple, and how to do that?
I would like to do this without using boost, if possible.
This is possible:
struct Functor
{
template<typename T>
void operator()(T& t) const { std::cout << t << std::endl; }
};
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_index(int, std::tuple<Tp...> &, FuncT)
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_index(int index, std::tuple<Tp...>& t, FuncT f)
{
if (index == 0) f(std::get<I>(t));
for_index<I + 1, FuncT, Tp...>(index-1, t, f);
}
auto t = make_tuple(1, 2, "abc", "def", 4.0f);
int i = 2; // for example
for_index(i, t, Functor());
This code will print:
abc
Working sample on ideone: sample
You cannot. That's not what a tuple is for. If you need dynamic access to an element, use std::array<T,N>, which is almost identical to std::tuple<T,...,T> but gives you the dynamic [i]-operator; or even a fully dynamic container like std::vector<T>.
This is probably not what OP wants, but anyway, it is possible to return the i-th element using a run-time i provided you return a variant type such as boost::variant or boost::any,
#include <tuple>
#include <stdexcept>
#include <boost/variant.hpp>
template <size_t n, typename... T>
boost::variant<T...> dynamic_get_impl(size_t i, const std::tuple<T...>& tpl)
{
if (i == n)
return std::get<n>(tpl);
else if (n == sizeof...(T) - 1)
throw std::out_of_range("Tuple element out of range.");
else
return dynamic_get_impl<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
}
template <typename... T>
boost::variant<T...> dynamic_get(size_t i, const std::tuple<T...>& tpl)
{
return dynamic_get_impl<0>(i, tpl);
}
For example:
#include <string>
#include <iostream>
int main()
{
std::tuple<int, float, std::string, int> tpl {4, 6.6, "hello", 7};
for (size_t i = 0; i < 5; ++ i)
std::cout << i << " = " << dynamic_get(i, tpl) << std::endl;
return 0;
}
will print:
0 = 4
1 = 6.6
2 = hello
3 = 7
terminate called after throwing an instance of 'std::out_of_range'
what(): Tuple element out of range.
Aborted
(The boost::variant<T...> requires g++ 4.7)
The question here, what would be the type return type if that would be possible? It has to be known at compile time, but tuple may contain elements of different types.
Let's assume we have a tuple of three elements:
auto tuple = std::make_tuple(10, "", A());
using tuple_type = decltype(tuple);
Apparently, getting N-th element doesn't make much sense. What type would it be? It's not known until runtime. However, rather than getting N-th element you can apply a function to it, given that all elements support some common protocol:
void process(int n)
{
if (n == 0)
func(std::get<0>(tuple));
else if (n == 1)
func(std::get<1>(tuple));
else if (n == 2)
func(std::get<2>(tuple));
}
This code "dynamically" processes element, given the index n. The common protocol in this example is function func which can do something meaningful with all possible types used in the tuple.
However, writing such code by hand is tedious, we want to make it more generic. Let's start with extracting the application function, so we can reuse same process function for different functors:
template<template<typename > class F>
void process(int n)
{
if (n == 0)
{
using E = typename std::tuple_element<0, tuple_type>::type;
F<E>::apply(std::get<0>(tuple));
}
else if (n == 1)
{
using E = typename std::tuple_element<1, tuple_type>::type;
F<E>::apply(std::get<1>(tuple));
}
else if (n == 2)
{
using E = typename std::tuple_element<2, tuple_type>::type;
F<E>::apply(std::get<2>(tuple));
}
}
In this case F could be implemented as something like:
// Prints any printable type to the stdout
struct printer
{
static void apply(E e)
{
std::cout << e << std::endl;
}
}
Let's make compiler to generate all of that code, let's make it generic:
constexpr static std::size_t arity = std::tuple_size<tuple_type>::value;
template<int N>
struct wrapper
{
template<template<typename, typename ... > class F>
static void apply_to(tuple_type& tuple, int idx)
{
if (idx)
// Double recursion: compile and runtime.
// Compile-time "recursion" will be terminated once
// we reach condition N == tuple arity
// Runtime recursion terminates once idx is zero.
wrapper<N + 1>::template apply_to<F>(tuple, idx - 1);
else
{
// idx == 0 (which means original index is equal to N).
using E = typename std::tuple_element<N, tuple_type>::type;
F<E>::apply(std::get<N>(tuple));
}
}
};
// Termination condition: N == arity.
template<>
struct wrapper<arity>
{
template<template<typename, typename ... > class F>
static void apply_to(tuple_type&, int)
{
// Throw exception or something. Index is too big.
}
};
Usage:
wrapper<0>::template apply_to<printer>(tuple, 2);
Making it completely generic is another story, though. At least it needs to be independent of the tuple type. Then, you probably want to generify return type of the functor, so you can return meaningful result. Third, making functor to accept extra parameters.
P.S. I am not real C++ developer, so the approach above could be total nonsence. However, I found it useful for my microcontroller project where I want as much as possible to be resolved at compile time and yet be generic enough, so I can shuffle things around easily. For example, a "menu" in my project is basically a tuple of "actions", there each action is a separate class which supports simple protocol like "print your label at current position on LCD" and "activate and run your UI loop".
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
I am a little confused about how can I read each argument from the tuple by using variadic templates.
Consider this function:
template<class...A> int func(A...args){
int size = sizeof...(A);
.... }
I call it from the main file like:
func(1,10,100,1000);
Now, I don't know how I have to extend the body of func to be able to read each argument separately so that I can, for example, store the arguments in an array.
You have to provide overrides for the functions for consuming the first N (usually one) arguments.
void foo() {
// end condition argument pack is empty
}
template <class First, class... Rest>
void foo(First first, Rest... rest) {
// Do something with first
cout << first << endl;
foo(rest...); // Unpack the arguments for further treatment
}
When you unpack the variadic parameter it finds the next overload.
Example:
foo(42, true, 'a', "hello");
// Calls foo with First = int, and Rest = { bool, char, char* }
// foo(42, Rest = {true, 'a', "hello"}); // not the real syntax
Then next level down we expand the previous Rest and get:
foo(true, Rest = { 'a', "hello"}); // First = bool
And so on until Rest contains no members in which case unpacking it calls foo() (the overload with no arguments).
Storing the pack if different types
If you want to store the entire argument pack you can use an std::tuple
template <class... Pack>
void store_pack(Pack... p) {
std::tuple<Pack...> store( p... );
// do something with store
}
However this seems less useful.
Storing the pack if it's homogeneous
If all the values in the pack are the same type you can store them all like this:
vector<int> reverse(int i) {
vector<int> ret;
ret.push_back(i);
return ret;
}
template <class... R>
vector<int> reverse(int i, R... r) {
vector<int> ret = reverse(r...);
ret.push_back(i);
return ret;
}
int main() {
auto v = reverse(1, 2, 3, 4);
for_each(v.cbegin(), v.cend(),
[](int i ) {
std::cout << i << std::endl;
}
);
}
However this seems even less useful.
If the arguments are all of the same type, you could store the arguments in an array like this (using the type of the first argument for the array):
template <class T, class ...Args>
void foo(const T& first, const Args&... args)
{
T arr[sizeof...(args) + 1] = { first, args...};
}
int main()
{
foo(1);
foo(1, 10, 100, 1000);
}
If the types are different, I suppose you could use boost::any but then I don't see how you are going to find out outside of the given template, which item is of which type (how you are going to use the stored values).
Edit:
If the arguments are all of the same type and you want to store them into a STL container, you could rather use the std::initializer_list<T>. For example, Motti's example of storing values in reverse:
#include <vector>
#include <iostream>
#include <iterator>
template <class Iter>
std::reverse_iterator<Iter> make_reverse_iterator(Iter it)
{
return std::reverse_iterator<Iter>(it);
}
template <class T>
std::vector<T> reverse(std::initializer_list<T> const & init)
{
return std::vector<T>(make_reverse_iterator(init.end()), make_reverse_iterator(init.begin()));
}
int main() {
auto v = reverse({1, 2, 3, 4});
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << std::endl;
}
}
For sticking into an array if the arguments have different types, you can use also std::common_type<>
template<class ...A> void func(A ...args){
typedef typename std::common_type<A...>::type common;
std::array<common, sizeof...(A)> a = {{ args... }};
}
So for example, func(std::string("Hello"), "folks") creates an array of std::string.
If you need to store arguments in the array you could use array of boost::any as follows:
template<typename... A> int func(const A&... args)
{
boost::any arr[sizeof...(A)] = { args... };
return 0;
}