I am writing a function that stores a parameter pack into a std::any of tuple, and I need to allocate a pointer array void* arguments[] to each item of the tuple. How can I do that at compile time?
template <typename... ArgsT>
void func(ArgsT&&... args) {
// any will be the storage for the argument
std::any any = std::make_tuple(std::forward<ArgsT>(args)...);
// here I need a pointer array with each ptrs[i] to (void*)&std::get<i>( std::get<WhatTupleTypeHere?>(any) )
void* arguments[sizeof...(ArgsT)] = { ??? };
}
For example, if I have:
fun(1, 2.4, std::string("hello"))
Then arguments should go as follows:
std::any storage = std::tuple<int, float, std::string>(1, 2.4, "hello");
auto& tuple = std::tuple<int, float, std::string>>(storage);
void* arguments[3] = {
(void*)&std::get<0>(tuple),
(void*)&std::get<1>(tuple),
(void*)&std::get<2>(tuple)
};
My compiler supports c++17.
Full example including test cases with a few minor changes (e.g., static in func) to help with testing/lifetime issues, but I think I hit your requirements.
#include <any>
#include <iostream>
#include <string>
#include <tuple>
namespace {
namespace detail {
template <std::size_t INDEX, typename ...Ts>
void fill_array(void ** arguments, std::tuple<Ts...> & data) {
if constexpr(INDEX < sizeof...(Ts)) {
arguments[INDEX] = (void *)&std::get<INDEX>(data);
fill_array<INDEX + 1>(arguments, data);
}
}
}
template <typename... ArgsT>
void** func(ArgsT&&... args) {
// any will be the storage for the argument
static std::any any = std::make_tuple(std::forward<ArgsT>(args)...);
// here I need a pointer array with each ptrs[i] to (void*)&std::get<i>( std::get<WhatTupleTypeHere?>(any) )
static void* arguments[sizeof...(ArgsT)];
detail::fill_array<0>(arguments, std::any_cast<std::tuple<ArgsT...>&>(any));
return arguments;
}
}
int main() {
auto arguments = func(1, 2.4, std::string("hello"));
std::cout << *((int*)arguments[0]) << '\n'
<< *((double*)arguments[1]) << '\n'
<< *((std::string*)arguments[2]) << '\n';
return 0;
}
The trick is to use fill_array since we need compile-time constants when using std::get. We'll extract the tuple from your any, and then it's fairly straightforward code as far as templates go.
Related
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;
}
template<typename... Args, typename Action>
void execute(const Action& _action) {
using all_components = std::tuple<Args...>;
auto tuple = std::tie();
for (int s = 0; s < all_components.size(); s++) {
tuple = std::tuple_cat(tuple, *reinterpret_cast<get<s>(all_components)*>(data[s]);
}
std::apply(_action, tuple);
}
I want to access the Parameter types, so I can cast my data that is saved in vector<char> type. In the type the function action needs it to have. But I'm not sure if how to access them. This was my idea, but it doesn't work, as the get function returns error: syntax error: unexpected token 'identifier', expected 'type specifier', I get what the error means, no explanation needed, but I need an alternative solution.
Couple of things:
all_components is a type, it does not have size() method. You can use sizeof...(Args) to obtain the length of the pack.
std::get requires a tuple object. Since it is a cast, thus unevaluated context, you can use std::declval<all_components>() to obtain the tuple.
Because std::get returns a value, you have to convert it to a type for it to be casted to.
#include <tuple>
#include <functional>
template<typename... Args, typename Action>
void execute(const Action& _action) {
using all_components = std::tuple<Args...>;
auto tuple = std::tie();
for (int s = 0; s < sizeof...(Args); s++) {
tuple = std::tuple_cat(tuple, *reinterpret_cast<decltype(std::get<s>(std::declval<all_components>()))*>(data[s]);
}
std::apply(_action, tuple);
}
But
you are still missing data.
Because s is used in a template, it has to be constexpr, so the ordinary loop won't compile.
Is sizeof of every Arg 1? If not, the deserialization is wrong.
My wild guess is that the data is tightly packed inside the vector. In that case you need something like this:
#include <tuple>
#include <functional>
template<typename...Args>
constexpr auto data_indices(){
std::array is{std::size_t(0), sizeof(Args)...};
for(std::size_t i=1;i<is.size();++i){
is[i]+=is[i-1];
}
return is;
}
template<typename...Args,std::size_t...Is>
auto get_tuple(std::index_sequence<Is...>, const char* data){
auto indices = data_indices<Args...>();
return std::tuple{*reinterpret_cast<const Args*>(data+indices[Is])...};
}
template<typename... Args, typename Action>
void execute(const Action& _action, const char* data) {
std::apply(_action, get_tuple<Args...>(std::make_index_sequence<sizeof...(Args)>{},data));
}
#include <cstring>
#include <iostream>
void foo(int x, double y){
std::cout<<x<<' '<<y<<'\n';
}
int main(){
std::array<char,sizeof(int)+sizeof(double)> arr;
int x = 12;
double y = 24.0;
std::memcpy(arr.data(),&x,sizeof(x));
std::memcpy(arr.data()+sizeof(x), &y,sizeof(y));
execute<int,double>(foo,arr.data());
}
Unless you are using placement new to put the elements into the array, you have to explicitly copy them to the tuple, otherwise you are breaking the strict aliasing rule. So:
template<typename...Args,std::size_t...Is>
auto get_tuple(std::index_sequence<Is...>, const char* data){
auto indices = data_indices<Args...>();
std::tuple<Args...> tuple;
(std::memcpy(&std::get<Is>(tuple), data+indices[Is], sizeof(Args)), ...);
return tuple;
}
What I'm trying to achieve is creating a struct which stores any kind of method. I can later call struct_object.run() to run the method I've stored.
This method can return any kind of value and, most importantly, use any amount of parameters; however, I can't get around the "any amount of parameters" issue.
Mind you, the following code doesn't even build, mostly because I have no clue on what the correct syntax would be like.
ApplicationPair.h
template<typename T, typename... Args>
struct ApplicationPair
{
ApplicationPair(boost::function<T()> func, Args... arguments )
{
_func = func(Args::arguments...);
}
ApplicationPair() = delete;
void run();
boost::function<T(Args...)> _func;
};
#endif
And then, what I'd like to do is the following:
main.cpp
template<typename T, typename... Args>
void ApplicationPair<T,Args...>::run()
{
this->_func;
}
//TEST
int counter = 0;
void HelloWorld()
{
std::cout << "HelloWorld\n";
}
void printNumber(int i)
{
std::cout << "Print: " << i << std::endl;
}
void increaseCounter(int x)
{
counter+=x;
}
int main()
{
ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);
p1.run();
p2.run();
p3.run();
return 0;
}
Basically, the methods I want to store shouldn't be modified or adapted in any way: I want to be able to create any kind of method without caring about the fact that struct ApplicationPair will store it for its own personal use.
All I get with this though is a long string of errors like:
error: in declaration ‘typename boost::enable_if_c<(! boost::is_integral::value), boost::function&>::type boost::function::operator=(Functor)’
In the below line:
ApplicationPair<void> p2(printNumber, 5);
you have to specify all types in template arguments list, not only void as return type, int as argument of constructor should also be added. Now args... is empty. What is wrong. The same with p3.
Make constructor as templated method taking paramters pack as argument for your callable:
template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
_func = boost::bind(std::forward<F>(func),arguments...);
}
then args... can be deduced when invoking constructor. Your class template takes only a type for return value.
template<class Ret>
struct ApplicationPair {
template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
_func = boost::bind(std::forward<F>(func),arguments...);
}
ApplicationPair() = delete;
void run() {
this->_func();
}
boost::function<Ret()> _func;
};
In constructor boost::bind is used to bind passed parameters to callable. You don't store parameters anywhere, therefore they must be bound in functor created by boost::bind.
Uses:
ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);
Demo
Don't use boost::bind, it is limited to handle only max 9 arguments.
You've already gotten an answer but here's a C++17 alternative capable of deducing the return value type as well as the argument types of the function using a deduction guide, making both the return type and argument types part of the ApplicationPair<> type. I've chosen to store the arguments separately in a std::tuple<Args...>.
boost::function can be replaced with std::function in this example in case you later decide to go with the standard:
#include <boost/function.hpp>
#include <iostream>
#include <type_traits>
#include <tuple>
template<typename T, typename... Args>
struct ApplicationPair {
ApplicationPair() = delete;
ApplicationPair(Func func, Args... args) :
_func(func),
// store the arguments for later use
arguments(std::make_tuple(std::forward<Args>(args)...))
{}
decltype(auto) run() { // I'd rename this: decltype(auto) operator()()
return std::apply(_func, arguments);
}
boost::function<T(Args...)> _func;
std::tuple<Args...> arguments;
};
// deduction guide
template<typename Func, typename... Args>
ApplicationPair(Func, Args...) ->
ApplicationPair<std::invoke_result_t<Func, Args...>, Args...>;
int counter = 0;
void HelloWorld()
{
std::cout << "HelloWorld\n";
}
void printNumber(int i)
{
std::cout << "Print: " << i << std::endl;
}
int increaseCounter(int x) // changed return type for demo
{
counter+=x;
return counter;
}
int main()
{
// full deduction using the deduction guide
ApplicationPair p1(HelloWorld);
ApplicationPair p2(printNumber, 5);
ApplicationPair p3(increaseCounter, 10);
p1.run();
p2.run();
std::cout << p3.run() << '\n';
std::cout << p3.run() << '\n';
}
I've found this interesting code here on stackoverflow from:
Using a STL map of function pointers
template<typename T,typename... Args>
T searchAndCall(std::string s1, Args&&... args){
// ....
// auto typeCastedFun = reinterpret_cast<T(*)(Args ...)>(mapVal.first);
auto typeCastedFun = (T(*)(Args ...))(mapVal.first);
//compare the types is equal or not
assert(mapVal.second == std::type_index(typeid(typeCastedFun)));
return typeCastedFun(std::forward<Args>(args)...);
}
};
Basically, mapVal is a map of function pointers casted to void(*)(void) that will be casted back to their original type with this function. What I would like to do know is how typeCastedFun will be deduced when you don't specify the template parameters.
For instance, let's suppose that you had:
int f(const MyClass& a, MyClass b) {...}
... if you have:
MyClass first, second;
searchAndCall<int>(first, second);
What Args... parameter will be deduced? if I recall correctly, using the function casted back to a function with a different signature compared to the original one, should yield undefined behavior. Is there any other alternative?
What I would like to do is a way to store the type of the function somewhere and use this information to do the correct cast. Everything in the most efficient way.
Thanks
[edit1]
More specifically, I'm trying to build a kind of generic function dispatcher, able to call functions (templated with an enum class value) with different signatures using a lookup table for efficiency reasons. No boost::any as it internally uses a new
[edit2] Use of macros is not allowed
The key problem is that by taking the calling argument types directly, and attempting to cast the function pointer, you are losing all implicit conversions.
Your function signature has to match exactly, or you will get UB if you try to call it. And there is generally no way to get the signature from the args without manually specifying it at the call site.
One workaround to try would be to add a wrapper lambda which takes standardized args with pre-specified implicit coversions applied, e.g. T -> const T&, and possibly numeric types -> double.
Then, when you look up the function, you can cast it to use these standardized args, and the calling args will be implicitly converted.
This would rule out functions taking rvalue refs and non-const references, but I don't thing this is unreasonable for a function that you don't know the signature of, unless you want to disregard const-correctness completely.
Also, other implicit conversions wouldn't happen, e.g. Derived& -> Base&, or char* -> std::string, and I don't think there would be an easy way to make that happen without creating extra limitations.
Overall, it's definitely a tricky thing to do in c++, and anything you try will be hacky. This way should be decent enough. The performance overhead of one extra function call (which can be inlined), and possibly some extraneous argument conversions will be overshadowed by the unavoidable RTTI checking.
Here is a sample implementation (also here on ideone):
#include <unordered_map>
#include <typeinfo>
#include <typeindex>
#include <string>
#include <type_traits>
#include <iostream>
#include <assert.h>
#include <cxxabi.h>
#include <sstream>
#include <stdexcept>
template <typename Func, Func f>
struct store_func_helper;
// unix-specific
std::string demangle(const std::string& val) {
int status;
char *realname;
std::string strname = realname = abi::__cxa_demangle(val.c_str(), 0, 0, &status);
free(realname);
return strname;
}
// args will be implicitly converted to arg<T>::type before calling function
// default: convert to const Arg&
template <typename Arg, typename snifae=void>
struct arg {
using type = const Arg&;
};
// numeric types: convert to double.
template <typename Arg>
struct arg <Arg, typename std::enable_if<std::is_arithmetic<Arg>::value, void>::type> {
using type = double;
};
// set more special arg types here.
// Functions stored in the map are first wrapped in a lambda with this signature.
template <typename Ret, typename... Arg>
using func_type = Ret(*)(typename arg<Arg>::type...);
class func_map {
template <typename Func, Func f>
friend class store_func_helper;
public:
template <typename Func, Func f>
void store(const std::string& name){
store_func_helper<Func, f>::call(this, name );
}
template<typename Ret, typename... Args>
Ret call(std::string func, Args... args){
using new_func_type = func_type<Ret, Args...>;
auto& mapVal = m_func_map.at(func);
if (mapVal.second != std::type_index(typeid(new_func_type))){
std::ostringstream ss;
ss << "Error calling function " << func << ", function type: "
<< demangle(mapVal.second.name())
<< ", attempted to call with " << demangle(typeid(new_func_type).name());
throw std::runtime_error(ss.str());
}
auto typeCastedFun = (new_func_type)(mapVal.first);
//args will be implicitly converted to match standardized args
return typeCastedFun(std::forward<Args>(args)...);
};
private:
std::unordered_map<std::string, std::pair<void(*)(),std::type_index> > m_func_map;
};
#define FUNC_MAP_STORE(map, func) (map).store<decltype(&func),&func>(#func);
template <typename Ret, typename... Args, Ret(*f)(Args...)>
struct store_func_helper<Ret(*)(Args...), f> {
static void call (func_map* map, const std::string& name) {
using new_func_type = func_type<Ret, Args...>;
// add a wrapper function, which takes standardized args.
new_func_type lambda = [](typename arg<Args>::type... args) -> Ret {
return (*f)(args...);
};
map->m_func_map.insert(std::make_pair(
name,
std::make_pair((void(*)()) lambda, std::type_index(typeid(lambda)))
));
}
};
//examples
long add (int i, long j){
return i + j;
}
int total_size(std::string arg1, const std::string& arg2) {
return arg1.size() + arg2.size();
}
int main() {
func_map map;
FUNC_MAP_STORE(map, total_size);
FUNC_MAP_STORE(map, add);
std::string arg1="hello", arg2="world";
std::cout << "total_size: " << map.call<int>("total_size", arg1, arg2) << std::endl;
std::cout << "add: " << map.call<long>("add", 3, 4) << std::endl;
}
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;
}