I'm looking at the following problem:
I get strings that are formatted like this:
functionname_parameter1_parameter2_parameter3
otherfunctionname_parameter1_parameter2
.
.
.
and i would like to call the function with the given parameters.
So let's say i have a function test:
void test(int x, float y, std::string z) {}
and i get a message:
test_5_2.0_abc
then i would like the function test to be automatically invoked like this:
test(5, 2.0, "abc");
Do you have any hints on how to accomplish this in C++?
Update: Updated stream_function to fix the argument-evaluation-order problem #Nawaz mentioned in the comments, and also removed the std::function for improved efficiency. Note that the evaluation-order fix only works for Clang, as GCC doesn't follow the standard here. An example for GCC, with manual order-enforcement, can be found here.
This is generally not that easy to accomplish. I wrote a little wrapper class around std::function once that extracts the arguments from a std::istream. Here's an example using C++11:
#include <map>
#include <string>
#include <iostream>
#include <sstream>
#include <functional>
#include <stdexcept>
#include <type_traits>
// for proper evaluation of the stream extraction to the arguments
template<class R>
struct invoker{
R result;
template<class F, class... Args>
invoker(F&& f, Args&&... args)
: result(f(std::forward<Args>(args)...)) {}
};
template<>
struct invoker<void>{
template<class F, class... Args>
invoker(F&& f, Args&&... args)
{ f(std::forward<Args>(args)...); }
};
template<class F, class Sig>
struct stream_function_;
template<class F, class R, class... Args>
struct stream_function_<F, R(Args...)>{
stream_function_(F f)
: _f(f) {}
void operator()(std::istream& args, std::string* out_opt) const{
call(args, out_opt, std::is_void<R>());
}
private:
template<class T>
static T get(std::istream& args){
T t; // must be default constructible
if(!(args >> t)){
args.clear();
throw std::invalid_argument("invalid argument to stream_function");
}
return t;
}
// void return
void call(std::istream& args, std::string*, std::true_type) const{
invoker<void>{_f, get<Args>(args)...};
}
// non-void return
void call(std::istream& args, std::string* out_opt, std::false_type) const{
if(!out_opt) // no return wanted, redirect
return call(args, nullptr, std::true_type());
std::stringstream conv;
if(!(conv << invoker<R>{_f, get<Args>(args)...}.result))
throw std::runtime_error("bad return in stream_function");
*out_opt = conv.str();
}
F _f;
};
template<class Sig, class F>
stream_function_<F, Sig> stream_function(F f){ return {f}; }
typedef std::function<void(std::istream&, std::string*)> func_type;
typedef std::map<std::string, func_type> dict_type;
void print(){
std::cout << "print()\n";
}
int add(int a, int b){
return a + b;
}
int sub(int a, int b){
return a - b;
}
int main(){
dict_type func_dict;
func_dict["print"] = stream_function<void()>(print);
func_dict["add"] = stream_function<int(int,int)>(add);
func_dict["sub"] = stream_function<int(int,int)>(sub);
for(;;){
std::cout << "Which function should be called?\n";
std::string tmp;
std::cin >> tmp;
auto it = func_dict.find(tmp);
if(it == func_dict.end()){
std::cout << "Invalid function '" << tmp << "'\n";
continue;
}
tmp.clear();
try{
it->second(std::cin, &tmp);
}catch(std::exception const& e){
std::cout << "Error: '" << e.what() << "'\n";
std::cin.ignore();
continue;
}
std::cout << "Result: " << (tmp.empty()? "none" : tmp) << '\n';
}
}
Compiles under Clang 3.3 and works as expected (small live example).
Which function should be called?
a
Invalid function 'a'
Which function should be called?
add
2
d
Error: 'invalid argument to stream_function'
Which function should be called?
add
2
3
Result: 5
Which function should be called?
add 2 6
Result: 8
Which function should be called?
add 2
6
Result: 8
Which function should be called?
sub 8 2
Result: 6
It was fun to hack that class together again, hope you enjoy. Note that you need to modify the code a little to work for your example, since C++ IOstreams have whitespace as delimiter, so you'd need to replace all underscores in your message with spaces. Should be easy to do though, after that just construct a std::istringstream from your message:
std::istringstream input(message_without_underscores);
// call and pass 'input'
You pretty much can't, C++ doesn't have any kind of reflection on functions.
The question then is how close you can get. An interface like this is pretty plausible, if it would suit:
string message = "test_5_2.0_abc";
string function_name = up_to_first_underscore(message);
registered_functions[function_name](message);
Where registered_functions is a map<string,std::function<void,string>>, and you have to explicitly do something like:
registered_functions["test"] = make_registration(test);
for each function that can be called in this way.
make_registration would then be a fairly hairy template function that takes a function pointer as a parameter and returns a std::function object that when called splits the string into chunks, checks that there are the right number there, converts each one to the correct parameter type with a boost::lexical_cast, and finally calls the specified function. It would know the "correct type" from the template argument to make_registration -- to accept arbitrarily many parameters this would have to be a C++11 variadic template, but you can fake it with:
std::function<void,string> make_registration(void(*fn)(void));
template <typename T>
std::function<void,string> make_registration(void(*fn)(T));
template <typename T, U>
std::function<void,string> make_registration(void(*fn)(T, U));
// etc...
Dealing with overloads and optional parameters would add further complication.
Although I don't know anything about them, I expect that there are C++ support frameworks out there for SOAP or other RPC protocols, that might contain some relevant code.
What you are looking for is reflection. And it is not possible in C++. C++ is designed with speed in mind. If you require inspection of a library or code and then identify the types in it and invoke methods associated with those types (usually classes) then I am afraid it is not possible in C++.
For further reference you can refer to this thread.
How can I add reflection to a C++ application?
http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI
Why does C++ not have reflection?
You could parse the string, separate the arguments and send them to the function with no problem, but what you cannot do is reference the function with its name on a string, because the function doesn't have a name anymore at runtime.
You could have a if-else if chain that checks for the function name, and then parse the arguments and call the specific function.
I modified #Xeo's code to work with gcc properly, so it ensures the parameters are pulled in the right order. I'm only posting this since it took me a while to understand the original code and splice in the order-enforcement. Full credit should still go to #Xeo. If I find anything wrong with my implementation I'll come back and edit, but thus far in my testing I haven't seen any problems.
#include <map>
#include <string>
#include <iostream>
#include <sstream>
#include <functional>
#include <stdexcept>
#include <type_traits>
#include <tuple>
template<class...> struct types{};
// for proper evaluation of the stream extraction to the arguments
template<class ReturnType>
struct invoker {
ReturnType result;
template<class Function, class... Args>
invoker(Function&& f, Args&&... args) {
result = f(std::forward<Args>(args)...);
}
};
template<>
struct invoker<void> {
template<class Function, class... Args>
invoker(Function&& f, Args&&... args) {
f(std::forward<Args>(args)...);
}
};
template<class Function, class Sig>
struct StreamFunction;
template<class Function, class ReturnType, class... Args>
struct StreamFunction<Function, ReturnType(Args...)>
{
StreamFunction(Function f)
: _f(f) {}
void operator()(std::istream& args, std::string* out_opt) const
{
call(args, out_opt, std::is_void<ReturnType>());
}
private:
template<class T>
static T get(std::istream& args)
{
T t; // must be default constructible
if(!(args >> t))
{
args.clear();
throw std::invalid_argument("invalid argument to stream_function");
}
return t;
}
//must be mutable due to const of the class
mutable std::istream* _args;
// void return
void call(std::istream& args, std::string*, std::true_type) const
{
_args = &args;
_voidcall(types<Args...>{});
}
template<class Head, class... Tail, class... Collected>
void _voidcall(types<Head, Tail...>, Collected... c) const
{
_voidcall<Tail...>(types<Tail...>{}, c..., get<Head>(*_args));
}
template<class... Collected>
void _voidcall(types<>, Collected... c) const
{
invoker<void> {_f, c...};
}
// non-void return
void call(std::istream& args, std::string* out_opt, std::false_type) const {
if(!out_opt) // no return wanted, redirect
return call(args, nullptr, std::true_type());
_args = &args;
std::stringstream conv;
if(!(conv << _call(types<Args...>{})))
throw std::runtime_error("bad return in stream_function");
*out_opt = conv.str();
}
template<class Head, class... Tail, class... Collected>
ReturnType _call(types<Head, Tail...>, Collected... c) const
{
return _call<Tail...>(types<Tail...>{}, c..., get<Head>(*_args));
}
template<class... Collected>
ReturnType _call(types<>, Collected... c) const
{
return invoker<ReturnType> {_f, c...} .result;
}
Function _f;
};
template<class Sig, class Function>
StreamFunction<Function, Sig> CreateStreamFunction(Function f)
{
return {f};
}
typedef std::function<void(std::istream&, std::string*)> StreamFunctionCallType;
typedef std::map<std::string, StreamFunctionCallType> StreamFunctionDictionary;
This also works with Visual Studio 2013, have not tried earlier versions.
Related
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'm working on a class that schedules functions by binding them in a queue like this:
std::queue <void()> q;
template<typename R,typename... ArgsT>
void
schedule(R& fn, ArgsT&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
As you see I made the type in the queue void() to make it hold any type of function objects but now I can't get the return when I execute it. What should I do to solve this?
Note: I don't want to use an external library like boost and I don't know what kind of function the user will pass it.
Note: I don't want to use an external library like boost and I don't
know what's the kind of function the user will pass it.
What I usually do in this case is I use a base class (from Command pattern) in my queue, and then have two implementations, the one wrapping the bind, and the other (also wrapping the bind) exposing a function that allows getting the return value.
Here is an example of the returning specialization (at last):
#include <iostream>
#include <functional>
#include <memory>
struct ACmd
{
virtual void exec() = 0;
virtual ~ACmd(){}
};
template <class F>
struct Cmd;
template <class R, class ... Args>
struct Cmd<R(Args...)> : ACmd
{
R result_;
std::function<R()> func_;
template <class F>
Cmd(F&& func, Args&&... args): result_(), func_()
{
auto f = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
func_ = [f](){
return f();
};
}
virtual void exec(){
result_ = func_();
}
const R& getResult() const {return result_;}
};
// Make function for convenience, could return by value or ptr -
// - your choice
template <class R, class F, class ...Args>
Cmd<R(Args...)>* cmd(F&& func, Args&&... args)
{
return new Cmd<R(Args...)>(func, std::forward<Args>(args)...);
}
//... And overload for void...
int foo(int arg) {
return arg;
}
int main() {
auto x = cmd<int>(foo, 10);
x->exec();
std::cout << x->getResult() << std::endl;
return 0;
}
The result of the execution of each element in the queue, it is void, you have already defined it as such. If the functions passed in are required to return a value, then you would need to limit the type(s) returned to a fixed type, use utilities such as std::any, std::variant or some covariant types (possible with a std::unique_ptr or std::shared_ptr).
The simplest is to fix the return type (at compile time);
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
See the sample below.
The queue declaration needs to be a queue of objects, such as std::function objects. The return value from a bind can be assigned to a function and then used as expected.
std::function is a polymorphic function wrapper, it implements type erasure patterns akin to any, but is specifically designed for functions and other callable objects.
By way of example;
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(std::forward<R>(fn), std::forward<ArgsT>(args)...) );
};
int main()
{
schedule([](int a) { std::cout << "function called" << std::endl; return a; }, 42);
std::cout << q.front()() << std::endl;
}
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;
}
Given a callable object ( a function ) a, and an argument b ( or a series of arguments ), I would like to deduce the type returned from f considering that f is overloaded with multiple signatures.
one of my many attempts is
#include <iostream>
#include <cstdint>
#include <string>
#include <functional>
#include <utility>
#include <typeinfo>
int foo(uint32_t a) { return ((a + 0) * 2); }
bool foo(std::string a) { return (a.empty()); }
/*template <typename A, typename B> auto bar(A a, B b) -> decltype(a(b)) {
return (a(b));
}*/
/*template <typename A, typename B> decltype(std::declval<a(b)>()) bar(A a, B b)
{
return (a(b));
}*/
template <typename A, typename B> void bar(std::function<A(B)> a, B b) {
std::cout << a(b) << "\n";
}
int main() {
// the following 2 lines are trivial and they are working as expected
std::cout << foo(33) << "\n";
std::cout << typeid(decltype(foo(std::string("nothing")))).name() << "\n";
std::cout << bar(foo, 33) << "\n";
//std::cout << bar(foo, std::string("Heinz")) << "\n";
return (0);
}
and 2 templates options are commented out and included in the previous code.
I'm using declval result_of auto decltype without any luck.
How does the overloading resolution process works at compile time ?
If anyone wants to know why I'm trying to get creative with this, is that I'm trying to implement some Currying in C++11 in a workable/neat way.
The problem is that you can't easily create a function object from an overload set: when you state foo or &foo (the function decays into a function pointer in most case, I think) you don't get an object but you get an overload set. You can tell the compiler which overload you want by either calling it or providing its signature. As far as I can tell, you don't want either.
The only approach I'm aware of is to turn your function into an actual function object which makes the problem go away:
struct foo_object
{
template <typename... Args>
auto operator()(Args&&... args) -> decltype(foo(std::forward<Args>(args)...)) {
return foo(std::forward<Args>(args)...);
}
};
With that wrapper which is unfortunately needed for each name, you can trivially deduce the return type, e.g.:
template <typename Func, typename... Args>
auto bar(Func func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) {
// do something interesting
return func(std::forward<Args>(args)...);
}
int main() {
bar(foo_object(), 17);
bar(foo_object(), "hello");
}
It doesn't quite solve the problem of dealing with overload sets but it gets reasonably close. I experimented with this idea, essentially also for the purpose of currying in the context of an improved system of standard library algorithms and I'm leaning towards the algorithms actually being function objects rather than functions (this is desirable for various other reasons, too; e.g., you don't need to faff about when you want to customize on algorithm with another one).
If foo is overloaded, you need to use the following:
#include <type_traits>
int foo(int);
float foo(float);
int main() {
static_assert(std::is_same<decltype(foo(std::declval<int>())), int>::value, "Nope.");
static_assert(std::is_same<decltype(foo(std::declval<float>())), float>::value, "Nope2.");
}
If it's not, then this will suffice:
#include <type_traits>
bool bar(int);
int main() {
static_assert(std::is_same<std::result_of<decltype(bar)&(int)>::type, bool>::value, "Nope3.");
}
Yes, it is verbose because you're trying to explicitly extract what implicit ad-hoc overloading does for you.
This is actually already implemented for you std::result_of. Here is a possible implementation
template<class>
struct result_of;
// C++11 implementation, does not satisfy C++14 requirements
template<class F, class... ArgTypes>
struct result_of<F(ArgTypes...)>
{
typedef decltype(
std::declval<F>()(std::declval<ArgTypes>()...)
) type;
};
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