Attaching a "policy" to a function parameter - c++

In some code that I am writing, I have a bunch of C++ functions that I am trying to bind to lua in a generic way. (However, this question really has nothing to do with lua, it's really a C++ design question.)
The idea is I might have a C++ function with signature
int my_function(lua_State * L, std::string server, std::string message);
for instance, and I want to be able to push it to lua and expose it to user scripts.
However, lua can only directly receive functions of signature int (lua_State *). So, I have some templates which take a function pointer with signature like the above, and produce a function of signature int(lua_State *), which tries to read corresponding arguments off of the lua stack, and calls the target function with the parameters if it succeeds, and signals a lua error for the user if not.
That part is working, with some work, and this question is not about how to do that. (Please don't tell me about luabind, luabridge or other existing libs, for reasons I can't go into those are not appropriate for my project.)
Instead the issue I'm having now is that sometimes I want the input parameters to have slightly different semantics.
For instance, sometimes a parameter should be optional. I specialized my template for boost::optional in order to handle that case. So I can tag optional parameters with boost::optional in the function signature and the wrapper will know that if that parameter is missing, it's not an error, and it should just pass boost::none. Example:
int my_function(lua_State * L, boost::optional<std::string>, std::string message);
So the boost::optional template is being used kind of like a "policy" for the input here, and I basically like how that is working.
Here's an issue I'm less sure about though: handling of bool. In lua, there is a proper boolean type, however, lua also has a notion of contextually boolean, similar to C++'s notion of contextually convertible to bool. In lua, the values false and nil are falsy, and all other values are truthy.
Typically, when you have a c++ function that takes a bool, the user will expect that they can pass it any value and that your interface will respect the truthiness even if it's not strictly speaking a boolean value. However, in other cases, you might really want it to be interpretted strictly as a bool, and for it to be a user error if they don't pass true or false.
What I would like to be able to do is tag the "strictness" policy within the function declaration, so it would look like
int my_function(lua_State * L, strict<bool> b, std::string message);
Where, strict is some template like
template <typename T>
struct strict {
T value;
};
and this template really has meaning only in my wrapper machinery.
The thing that is annoying about this is that then you have to type b.value everywhere.
I thought about doing it like this:
template <typename T>
struct strict {
T value;
operator T & () & { return this->value; }
operator const T & () const & { return this->value; }
operator T && () && { return std::move(this->value); }
};
to allow a bunch of ref-qualified implicit conversions from strict<T> to references to the value.
How unsafe is this? I don't see major safety holes in this, although I've always adhered to the "implicit conversions are evil" mantra. I played around with it a little in test code and it doesn't seem to create ambiguities or problems, but there might be a clever way to make this do something very bad that I didn't think of.
If it's not a good idea, is there a better strategy than typing b.value everywhere, or some different way of rigging up the parameter policies that won't intrude upon the types?

something like this should do it.
The overloads of visit are what do the work. Note the recursive call from the optional version.
#include <iostream>
#include <string>
#include <utility>
#include <iomanip>
#include <boost/optional.hpp>
// some boilerplate
template <typename T, template <typename, typename...> class Tmpl> // #1 see note
struct is_derived_from_template
{
typedef char yes[1];
typedef char no[2];
static no & test(...);
template <typename ...U>
static yes & test(Tmpl<U...> const &);
static bool constexpr value = sizeof(test(std::declval<T>())) == sizeof(yes);
};
template<typename T, template <typename, typename...> class Tmpl>
static constexpr bool is_derived_from_template_v = is_derived_from_template<T, Tmpl>::value;
// i dont know much about a lua_state but I guess it's a bit like this...
struct lua_state {
void set_string(std::size_t index, const std::string& s) {
std::cout << "index " << index << " setting string " << std::quoted(s) << std::endl;
}
void set_missing(std::size_t index) {
std::cout << "index " << index << " setting missing" << std::endl;
}
void set_int(std::size_t index, int i) {
std::cout << "index " << index << " setting int " << i << std::endl;
}
};
// policies
template<class T, std::enable_if_t<std::is_same<std::decay_t<T>, std::string>::value>* = nullptr>
void visit(std::size_t index, lua_state* pstate, T&& value)
{
pstate->set_string(index, std::forward<T>(value));
}
template<class T, std::enable_if_t<std::is_same<std::decay_t<T>, int>::value>* = nullptr>
void visit(std::size_t index, lua_state* pstate, T&& value)
{
pstate->set_int(index, std::forward<T>(value));
}
// special policy for optional
template<class T,
std::enable_if_t<is_derived_from_template_v<std::decay_t<T>, boost::optional>>* = nullptr>
void visit(std::size_t index, lua_state* pstate, T&& value)
{
if (value)
{
visit(index, pstate, std::forward<T>(value).value());
}
else {
pstate->set_missing(index);
}
}
// helper function
template<std::size_t...Is, class Tuple>
void set_vars_impl(lua_state* pstate, std::index_sequence<Is...>, Tuple&& tuple)
{
using expand = int [];
void(expand{ 0,
((visit(Is, pstate, std::get<Is>(std::forward<Tuple>(tuple)))),0)...
});
}
template<class...Ts>
void set_vars(lua_state* pstate, Ts&&...ts)
{
set_vars_impl(pstate,
std::make_index_sequence<sizeof...(Ts)>(),
std::make_tuple(std::forward<Ts>(ts)...));
}
int main(int argc, const char * argv[]) {
lua_state ls;
boost::optional<std::string> a { };
boost::optional<std::string> b { std::string { "hello" }};
std::string c = "world";
int d = 0;
boost::optional<int> e;
boost::optional<int> f { 1 };
set_vars(std::addressof(ls), a, b, c, d, e, f);
return 0;
}
expected results:
index 0 setting missing
index 1 setting string "hello"
index 2 setting string "world"
index 3 setting int 0
index 4 setting missing
index 5 setting int 1

Related

Access std::vector<std::variant> value by index

I would like to access a member of std::vector<std::variant> by index. Considering the following snippet:
struct Data {
using data_types = std::variant<std::basic_string<char>, double, int>;
public:
template <class T>
void push_back(const T& t) {
m_data.push_back(t);
}
private:
std::vector<data_types> m_data;
};
int main()
{
Data d;
d.push_back(0);
d.push_back("string");
d.push_back(3.55);
}
I would like to access the values like d[0] (should return int) or d[1] (should return std::string).
What I have tried so far but what isn't working is to add the following public method to the existing struct:
template <class T>
T& operator[](const size_t &index) {
return std::visit([](const T& value) {
return static_cast<T>(value);
}, m_data[index]);
}
Any ideas how to achieve the desired result?
The type of an expression in C++ cannot depend on runtime parameters; basically it can only depend on types of the arguments, plus non-type template arguments.
So d[0] and d[1] must have the same type, as the type of the pieces of the expression are identical, and there are no non-type template arguments.
std::get<int>(d[0]) vs std::get<double>(d[1]) can differ in type.
std::get<1>(d[0]) vs std::get<2>(d[1]) can differ in type.
std::visit is a mechanism used to get around this; here, we create every a function object call, one for each possible type, and then pick one at runtime to actually call. However, the type returned from the visit still follows the above rule: it doesn't depend on what type is stored in the variant, and every possible type in the variant must have a valid instantiation of the function.
C++ type system is not a runtime type system. It is compile-time. Stuff like variant and dynamic_cast and any give some runtime exposure to it, but it is intentionally minimal.
If you are wanting to print the contents of a variant, you can do this:
std::visit([](auto& x){
std::cout << x;
}, d[0]);
the trick here is that each of the various types of variant have a lambda function body written for them (so they all must be valid). Then, at run time, the one actually in the variant is run.
You can also test the variant and ask if it has a specific type, either via std::get or manually.
bool has_int = std::visit([](auto& x){
return std::is_same_v<int, std::decay_t<decltype(x)>>::value;
}, d[0]);
this gives you a bool saying if d[0] has an int in it or not.
The next bit is getting insane. Please don't read this unless you fully understand how to use variants and want to know more:
You can even extract out the type index of the variant and pass that around as a run time value:
template<auto I>
using konstant_t = std::integral_constant<decltype(I),I>;
template<auto I>
constexpr konstant_t<I> konstant_v{};
template<auto...Is>
using venum_t = std::variant< konstant_t<Is>... >;
template<class Is>
struct make_venum_helper;
template<class Is>
using make_venum_helper_t = typename make_venum_helper<Is>::type;
template<std::size_t...Is>
struct make_venum_helper<std::index_sequence<Is...>>{
using type=venum_t<Is...>;
};
template<std::size_t N>
using make_venum_t = typename make_venum_helper<std::make_index_sequence<N>>::type;
template<std::size_t...Is>
constexpr auto venum_v( std::index_sequence<Is...>, std::size_t I ) {
using venum = make_venum_t<sizeof...(Is)>;
constexpr venum arr[]={
venum( konstant_v<Is> )...
};
return arr[I];
}
template<std::size_t N>
constexpr auto venum_v( std::size_t I ) {
return venum_v( std::make_index_sequence<N>{}, I );
}
template<class...Ts>
constexpr auto venum_v( std::variant<Ts...> const& v ) {
return venum_v< sizeof...(Ts) >( v.index() );
}
now you can do this:
using venum = make_venum_t<3>;
venum idx = venum_v(d[0]);
and idx holds the index of the engaged type in d[0]. This is only somewhat useful, as you still need std::visit to use it usefully:
std::visit([&](auto I) {
std::cout << std::get<I>( d[0] );
}, idx );
(within the lambda, I is a std::integral_constant, which can be constexpr converted to an integer.)
but lets you do some interesting things with it.
To extract a value from variant, use std::get:
struct Data
{
...
template <class T>
T& operator[](size_t index)
{
return std::get<T>(m_data[index]);
}
};
However, because this overloaded operator is a template, you can't use simple operator syntax to call it. Use the verbose syntax:
int main()
{
Data d;
d.push_back(0);
d.push_back("string");
d.push_back(3.55);
std::cout << d.operator[]<double>(2);
}
Or rename it to use a plain name instead of the fancy operator[].
Visitor pattern:
#include <iostream>
#include <string>
#include <variant>
#include <vector>
template <class ...Ts>
struct MultiVector : std::vector<std::variant<Ts...>> {
template <class Visitor>
void visit(std::size_t i, Visitor&& v) {
std::visit(v, (*this)[i]);
}
};
int main() {
MultiVector<std::string, int, double> vec;
vec.push_back(0);
vec.push_back("string");
vec.push_back(3.55);
vec.visit(2, [](auto& e) { std::cout << e << '\n'; });
}

casting a function back to the original signature using variadic args

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

Containers for different signature functions

I'm trying to programming in C++ a framework where the user can indicates a set of functions inside its program where he wants to apply a memoization strategy.
So let's suppose that we have 5 functions in our program f1...f5 and we want to avoid the (expensive) re-computation for the functions f1 and f3 if we already called them with the same input. Notice that each function can have different return and argument types.
I found this solution for the problem, but you can use only double and int.
MY SOLUTION
Ok I wrote this solution for my problem, but I don't know if it's efficient, typesafe or can be written in any more elegant way.
template <typename ReturnType, typename... Args>
function<ReturnType(Args...)> memoize(function<ReturnType(Args...)> func)
{
return ([=](Args... args) mutable {
static map<tuple<Args...>, ReturnType> cache;
tuple<Args...> t(args...);
auto result = cache.insert(make_pair(t, ReturnType{}));
if (result.second) {
// insertion succeeded so the value wasn't cached already
result.first->second = func(args...);
}
return result.first->second;
});
}
struct MultiMemoizator
{
map<string, boost::any> multiCache;
template <typename ReturnType, typename... Args>
void addFunction(string name, function < ReturnType(Args...)> func) {
function < ReturnType(Args...)> cachedFunc = memoize(func);
boost::any anyCachedFunc = cachedFunc;
auto result = multiCache.insert(pair<string, boost::any>(name,anyCachedFunc));
if (!result.second)
cout << "ERROR: key " + name + " was already inserted" << endl;
}
template <typename ReturnType, typename... Args>
ReturnType callFunction(string name, Args... args) {
auto it = multiCache.find(name);
if (it == multiCache.end())
throw KeyNotFound(name);
boost::any anyCachedFunc = it->second;
function < ReturnType(Args...)> cachedFunc = boost::any_cast<function<ReturnType(Args...)>> (anyCachedFunc);
return cachedFunc(args...);
}
};
And this is a possible main:
int main()
{
function<int(int)> intFun = [](int i) {return ++i; };
function<string(string)> stringFun = [](string s) {
return "Hello "+s;
};
MultiMemoizator mem;
mem.addFunction("intFun",intFun);
mem.addFunction("stringFun", stringFun);
try
{
cout << mem.callFunction<int, int>("intFun", 1)<<endl;//print 2
cout << mem.callFunction<string, string>("stringFun", " World!") << endl;//print Hello World!
cout << mem.callFunction<string, string>("TrumpIsADickHead", " World!") << endl;//KeyNotFound thrown
}
catch (boost::bad_any_cast e)
{
cout << "Bad function calling: "<<e.what()<<endl;
return 1;
}
catch (KeyNotFound e)
{
cout << e.what()<<endl;
return 1;
}
}
How about something like this:
template <typename result_t, typename... args_t>
class Memoizer
{
public:
typedef result_t (*function_t)(args_t...);
Memoizer(function_t func) : m_func(func) {}
result_t operator() (args_t... args)
{
auto args_tuple = make_tuple(args...);
auto it = m_results.find(args_tuple);
if (it != m_results.end())
return it->second;
result_t result = m_func(args...);
m_results.insert(make_pair(args_tuple, result));
return result;
}
protected:
function_t m_func;
map<tuple<args_t...>, result_t> m_results;
};
Usage is like this:
// could create make_memoizer like make_tuple to eliminate the template arguments
Memoizer<double, double> memo(fabs);
cout << memo(-123.456);
cout << memo(-123.456); // not recomputed
It's pretty hard to guess at how you're planning to use the functions, with or without memoisation, but for the container-of-various-function<>s aspect you just need a common base class:
#include <iostream>
#include <vector>
#include <functional>
struct Any_Function
{
virtual ~Any_Function() {}
};
template <typename Ret, typename... Args>
struct Function : Any_Function, std::function<Ret(Args...)>
{
template <typename T>
Function(T& f)
: std::function<Ret(Args...)>(f)
{ }
};
int main()
{
std::vector<Any_Function*> fun_vect;
auto* p = new Function<int, double, double, int> { [](double i, double j, int z) {
return int(i + j + z);
} };
fun_vect.push_back(p);
}
The problem with this is how to make it type-safe. Look at this code:
MultiMemoizator mm;
std::string name = "identity";
mm.addFunction(name, identity);
auto result = mm.callFunction(name, 1);
Is the last line correct? Does callFunction have the right number of parameters with the right types? And what is the return type?
The compiler has no way to know that: it has no way of understanding that name is "identity" and even if it did, no way to associate that with the type of the function. And this is not specific to C++, any statically-typed language is going to have the same problem.
One solution (which is basically the one given in Tony D's answer) is to tell the compiler the function signature when you call the function. And if you say it wrong, a runtime error occurs. That could look something like this (you only need to explicitly specify the return type, since the number and type of parameters is inferred):
auto result = mm.callFunction<int>(name, 1);
But this is inelegant and error-prone.
Depending on your exact requirements, what might work better is to use "smart" keys, instead of strings: the key has the function signature embedded in its type, so you don't have to worry about specifying it correctly. That could look something like:
Key<int(int)> identityKey;
mm.addFunction(identityKey, identity);
auto result = mm.callFunction(identityKey, 1);
This way, the types are checked at compile time (both for addFunction and callFunction), which should give you exactly what you want.
I haven't actually implemented this in C++, but I don't see any reason why it should be hard or impossible. Especially since doing something very similar in C# is simple.
you can use vector of functions with signature like void someFunction(void *r, ...) where r is a pointer to result and ... is variadic argument list. Warning: unpacking argument list is really inconvenient and looks more like a hack.
At first glance, how about defining a type that has template arguments that differ for each function, i.e.:
template <class RetType, class ArgType>
class AbstractFunction {
//etc.
}
have the AbstractFunction take a function pointer to the functions f1-f5 with template specializations different for each function. You can then have a generic run_memoized() function, either as a member function of AbstractFunction or a templated function that takes an AbstractFunction as an argument and maintains a memo as it runs it.
The hardest part will be if the functions f1-f5 have more than one argument, in which case you'll need to do some funky things with arglists as template parameters but I think C++14 has some features that might make this possible. An alternative is to rewrite f1-f5 so that they all take a single struct as an argument rather than multiple arguments.
EDIT: Having seen your problem 1, the problem you're running into is that you want to have a data structure whose values are memoized functions, each of which could have different arguments.
I, personally, would solve this just by making the data structure use void* to represent the individual memoized functions, and then in the callFunction() method use an unsafe type cast from void* to the templated MemoizedFunction type you need (you may need to allocate MemoizedFunctions with the "new" operator so that you can convert them to and from void*s.)
If the lack of type safety here irks you, good for you, in that case it may be a reasonable option just to make hand-written helper methods for each of f1-f5 and have callFunction() dispatch one of those functions based on the input string. This will let you use compile-time type checking.
EDIT #2: If you are going to use this approach, you need to change the API for callFunction() slightly so that callFunction has template args matching the return and argument types of the function, for example:
int result = callFunction<int, arglist(double, float)>("double_and_float_to_int", 3.5, 4);
and if the user of this API ever types the argument type or return types incorrectly when using callFunction... pray for their soul because things will explode in very ugly ways.
EDIT #3: You can to some extent do the type checking you need at runtime using std::type_info and storing the typeid() of the argument type and return type in your MemoizedFunction so that you can check whether the template arguments in callFunction() are correct before calling - so you can prevent the explosion above. But this will add a bit of overhead every time you call the function (you could wrap this in a IF_DEBUG_MODE macro to only add this overhead during testing and not in production.)

How to recover the type of a function pointer at runtime

In the code I register one or multiple function pointer in a manager class.
In this class I have a map that maps the argument types of the function to said function. It may look like so: std::map< std::vector<std::type_index> , void*>
template<typename Ret, typename... Args>
void Register(Ret(*function)(Args...)) {
void* v = (void*)function;
// recursively build type vector and add to the map
}
At runtime the code gets calls (from an external script) with an arbitrary number of arguments. These arguments can be read as primitive data types or as custom types that will be specified at compile time.
With every call from the script, I have to find out which function to call, and then call it. The former is easy and already solved (filling a vector with type_index in a loop), but I can't think of a solution for the latter.
My first approach was using variadic templates in recursion with an added template argument for each read type - but this turned out to be impossible since templates are constructed at compile time, and the arbitrary number of arguments is read at runtime.
Without variadic templates however, I don't see any possibility to achieve this. I considered boost::any instead of void*, but I didn't see how that would solve the need to cast back to the original type. I also thought of using std::function but that would be a templated type, so it could not be stored in a map for functions with different arguments.
(If it's unclear what I'm asking, think of LuaBinds possibility to register overloaded functions. I tried to understand how it's implemented there (without variadic templates, pre-C++11), but to no avail.)
Suppose you had the arguments in a vector of some kind, and a known function (fully).
You can call this. Call the function that does this invoke.
Next, work out how to do this for template<class... Args>. Augment invoke.
So you have written:
typedef std::vector<run_time_stuff> run_time_args;
template<class... Args>
void invoke( void(*func)(Args...), run_time_args rta )
at this point. Note that we know the types of the argument. I do not claim the above is easy to write, but I have faith you can figure it out.
Now we wrap things up:
template<class...Args>
std::function<void(run_time_args)> make_invoker(void(*func)(Args...)){
return [func](run_time_args rta){
invoke(func, rta);
};
}
and now instead of void* you store std::function<void(run_time_args)> -- invokers. When you add the function pointers to the mechanism you use make_invoker instead of casting to void*.
Basically, at the point where we have the type info, we store how to use it. Then where we want to use it, we use the stored code!
Writing invoke is another problem. It will probably involve the indexes trick.
Suppose we support two kinds of arguments -- double and int. The arguments at run time are then loaded into a std::vector< boost::variant<double, int> > as our run_time_args.
Next, let us extend the above invoke function to return an error in the case of parameter type mismatch.
enum class invoke_result {
everything_ok,
error_parameter_count_mismatch,
parameter_type_mismatch,
};
typedef boost::variant<int,double> c;
typedef std::vector<run_time_stuff> run_time_args;
template<class... Args>
invoke_result invoke( void(*func)(Args...), run_time_args rta );
now some boilerplate for the indexes trick:
template<unsigned...Is>struct indexes{typedef indexes type;};
template<unsigned Max,unsigned...Is>struct make_indexes:make_indexes<Max-1, Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Max>using make_indexes_t=typename make_indexes<Max>::type;
With that, we can write an invoker:
namespace helpers{
template<unsigned...Is, class... Args>
invoke_result invoke( indexes<Is...>, void(*func)(Args...), run_time_args rta ) {
typedef void* pvoid;
if (rta.size() < sizeof...(Is))
return invoke_result::error_parameter_count_mismatch;
pvoid check_array[] = { ((void*)boost::get<Args>( rta[Is] ))... };
for( pvoid p : check_array )
if (!p)
return invoke_result::error_parameter_type_mismatch;
func( (*boost::get<Args>(rts[Is]))... );
}
}
template<class... Args>
invoke_result invoke( void(*func)(Args...), run_time_args rta ) {
return helpers::invoke( make_indexes_t< sizeof...(Args) >{}, func, rta );
}
And that should work when func's args exactly match the ones passed in inside run_time_args.
Note that I was fast and loose with failing to std::move that std::vector around. And that the above doesn't support implicit type conversion. And I didn't compile any of the above code, so it is probably littered with typos.
I was messing around with variadic templates a few weeks ago and came up with a solution that might help you.
DELEGATE.H
template <typename ReturnType, typename ...Args>
class BaseDelegate
{
public:
BaseDelegate()
: m_delegate(nullptr)
{
}
virtual ReturnType Call(Args... args) = 0;
BaseDelegate* m_delegate;
};
template <typename ReturnType = void, typename ...Args>
class Delegate : public BaseDelegate<ReturnType, Args...>
{
public:
template <typename ClassType>
class Callee : public BaseDelegate
{
public:
typedef ReturnType (ClassType::*FncPtr)(Args...);
public:
Callee(ClassType* type, FncPtr function)
: m_type(type)
, m_function(function)
{
}
~Callee()
{
}
ReturnType Call(Args... args)
{
return (m_type->*m_function)(args...);
}
protected:
ClassType* m_type;
FncPtr m_function;
};
public:
template<typename T>
void RegisterCallback(T* type, ReturnType (T::*function)(Args...))
{
m_delegate = new Callee<T>(type, function);
}
ReturnType Call(Args... args)
{
return m_delegate->Call(args...);
}
};
MAIN.CPP
class Foo
{
public:
int Method(int iVal)
{
return iVal * 2;
}
};
int main(int argc, const char* args)
{
Foo foo;
typedef Delegate<int, int> MyDelegate;
MyDelegate m_delegate;
m_delegate.RegisterCallback(&foo, &Foo::Method);
int retVal = m_delegate.Call(10);
return 0;
}
Not sure if your requirements will allow this, but you could possibly just use std::function and std::bind.
The below solution makes the following assumptions:
You know the functions you want to call and their arguments
The functions can have any signature, and any number of arguments
You want to use type erasure to be able to store these functions and arguments, and call them all at a later point in time
Here is a working example:
#include <iostream>
#include <functional>
#include <list>
// list of all bound functions
std::list<std::function<void()>> funcs;
// add a function and its arguments to the list
template<typename Ret, typename... Args, typename... UArgs>
void Register(Ret(*Func)(Args...), UArgs... args)
{
funcs.push_back(std::bind(Func, args...));
}
// call all the bound functions
void CallAll()
{
for (auto& f : funcs)
f();
}
////////////////////////////
// some example functions
////////////////////////////
void foo(int i, double d)
{
std::cout << __func__ << "(" << i << ", " << d << ")" << std::endl;
}
void bar(int i, double d, char c, std::string s)
{
std::cout << __func__ << "(" << i << ", " << d << ", " << c << ", " << s << ")" << std::endl;
}
int main()
{
Register(&foo, 1, 2);
Register(&bar, 7, 3.14, 'c', "Hello world");
CallAll();
}

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