I've been reading about variadic templates, but having a hard time wrapping my mind around them.
The following code is from:
c++ - Call function with parameters extracted from string - Stack Overflow
Is it possible to do something like this with a string array, string vector, stringstream, or something to that effect instead of with an istream? istreams don't fit my usage. id like to pass in a string and split argument by spaces.
Can anyone point me in the right direction?
Code:
#include <map>
#include <string>
#include <iostream>
#include <sstream>
#include <functional>
#include <stdexcept>
#include <type_traits>
template<class F>
struct stream_function;
template<class R, class... Args>
struct stream_function<R(Args...)>{
typedef R func_type(Args...);
typedef std::function<func_type> function;
static unsigned const arity = sizeof...(Args);
template<class F>
stream_function(F const& f)
: _f(f) {}
void operator()(std::istream& args, std::string* out_opt) const{
call(args, out_opt, typename std::is_void<R>::type());
}
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 call(std::istream& args, std::string*, std::true_type) const{
// void return
_f(get<Args>(args)...);
}
void call(std::istream& args, std::string* out_opt, std::false_type) const{
// non-void return
if(!out_opt) // no return wanted, redirect
return call(args, 0, std::true_type());
R ret(_f(get<Args>(args)...));
std::stringstream conv;
if(!(conv << ret))
throw std::runtime_error("bad return in stream_function");
*out_opt = conv.str();
}
function _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 main(){
dict_type func_dict;
func_dict["print"] = stream_function<void()>(print);
func_dict["add"] = stream_function<int(int,int)>(add);
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';
}
}