How to write a generic convert function in c++? - c++

I need to read csv file using already written library that returns column value always as string, so as part of validation and further processing i need to convert that string value to appropriate type (which can be double, int, enum, bool, date etc.) and here is what I had written but this is giving error that there are multiple overloads for stod/stoi etc. Also is there any better approach to accomplish this task.
bool convertFunction(T a, R& b,std::function<R (T)> fx)
{
bool isConverted = true;
try
{
b = fx(a);
}
catch(const std::exception& e)
{
isConverted = false;
}
return isConverted;
}
int main() {
std::string x = "2.54";
double y = 0.0;
bool isValid = convertFunction(x,y,std::stod);
std::cout<<"value of y is "<<y<<std::endl;
return 0;
}

A totally generic approach might look as follows:
template <typename T>
bool convert(std::string const& text, T& value)
{
std::istringstream s(text);
s >> value;
char c;
return s && (s >> c, s.eof());
}
Reading yet another character is expected to fail with end-of-file flag to be set, this assures that the entire string has been read – then failing if trailing whitespace is available, though, so you might yet want to make the function tolerant against.

If you really want to go the template route...
The fix for your implementation is to wrap std::stod inside a lambda that takes a definitive set of parameters. Then assign that lambda to a std::function that matches what the template expects. I also updated the code to pass items by const reference a bit more consistently.
#include <string>
#include <functional>
#include <iostream>
template <typename T, typename R>
static bool convertFunction(const T& a, R& b, std::function<R (const T&)>& fx)
{
bool isConverted = true;
try
{
b = fx(a);
}
catch(const std::exception& e)
{
isConverted = false;
}
return isConverted;
}
int main() {
std::string x = "2.54";
double y = 0.0;
std::function<double (const std::string&)> S2D = [](const std::string& s) -> double {
return std::stod(s);
};
convertFunction(x, y, S2D);
std::cout<<"value of y is "<<y<<std::endl;
return 0;
}

Related

C++ Template is sending a "false argument" a bad practice?

std::stoi is throwing some errors in specific cases. I don't want to use try/catch block, so I googled a little bit about char convertion and saw that std::from_chars was doing exactly what I wanted, without those try/catch block.
Obviously, using std::from_chars directly works pretty well, but I don't like the syntax. So I started writing my own ToInt(), ToFloat(), etc. And was like : "ok, that sounds stupid, let's use template".
Here I am :
#include <string>
#include <charconv>
#include <iostream>
template <typename T>
T ToNumber(const char* str, T varType)
{
if (!str)
return 0;
T var = 0;
std::from_chars(str, str + strlen(str), var);
return var;
}
int main()
{
std::string t = "123.5";
auto a = ToNumber(t.c_str(), (int)0); // a will be an int (123)
float b = ToNumber(t.c_str(), (int)0); // b will store the value as int (123)
auto c = ToNumber(t.c_str(), (float)0); // c will be a float (123.5)
std::cout << a;
return 0;
}
It actually works, that is not the problem. But I was wondering... Is it a good practice to send a "false argument" (T varType) in order to get the cast done and enable auto ?
If not, what is the clever way to write such a function ?
Thanks in advance
You are not checking the return value of std::from_chars for failure, eg:
auto [p, ec] = std::from_chars(str, str + strlen(str), var);
if (ec != std::errc()) {
...
}
That said, another way to deal with the template argument T without using a type-casted input parameter is to simply specify the desired type explicitly at the call site instead, eg:
template <typename T>
T ToNumber(const char* str)
{
if (!str)
return T{};
T var{};
auto [p, ec] = std::from_chars(str, str + strlen(str), var);
if (ec != std::errc())
return T{};
return var;
}
auto a = ToNumber<int>(t.c_str());
float b = ToNumber<int>(t.c_str());
auto c = ToNumber<float>(t.c_str());
Otherwise, you can use template argument deduction via a reference output parameter (just like std::from_chars() does), eg:
template <typename T>
bool ToNumber(const char* str, T &var)
{
if (!str)
return false;
auto [p, ec] = std::from_chars(str, str + strlen(str), var);
return (ec == std::errc());
}
int a;
ToNumber(t.c_str(), a);
int tmp;
ToNumber(t.c_str(), tmp);
float b = tmp;
float c;
ToNumber(t.c_str(), c);

How to get function pointer from many functions and pass args to it?

I have many defined functions as follows, all return an int
int fn1(int x) {
return x;
}
int fn2(std::string x, int y, std::string z) {
// process string x and z
int x1 = process(x);
int z1 = process(z);
return x1 + y + z1;
}
// ... and many more similar functions
For some reasons, I need to implement a wrapper to call the above functions by function names,
int wrapper(std::string fn_name, some_struct_t data, std::vector<std::string> field_names) {
a_fn_ptr_type fn_ptr = nullptr; // <q1>: is this a right way to do?
// by fn_name, decide which fn to call
if (fn_name == "fn1") {
fn_ptr = &fn1;
}
if (fn_name == "fn2") {
fn_ptr = &fn2;
}
...
// given field_names, get the field from data, pass them to fn_ptr as args
for (auto field_name: field_names) {
std::any value = get_from_data(data, field_name, field_type); // field_type will be updated by this call, so that we know the value type.
// <q2>: but how to pass each value as arg to fn_ptr here?
}
}
The above code demonstrate what I want to achieve, and I have 2 questions (as pointed by <q1> and <q2>).
I'm not sure if the code is the right way to go, hope to get some advice from people, thanks!
Inspired by the comments:
A wrapper that takes some_struct_t data, std::vector<std::string> field_names. Assuming a
template <typename T>
T get_from_data(some_struct_t, std::string);
You have a function type
using func_t = std::function<int(const some_struct_t &, const std::vector<std::string>&)>;
which you can instantiate from functions via
template <typename... Args, size_t... Is>
auto wrap_impl(int(*func)(Args...), std::index_sequence<Is...>)
{
return [func](const some_struct_t & data, const std::vector<std::string>& field_names)
{ return func(get_from_data<Args>(data, field_names.at(Is))...); };
}
template <typename... Args>
func_t wrap(int(*func)(Args...))
{
return wrap_impl(func, std::index_sequence_for<Args...>{});
}
and then you can have a
std::map<std::string, func_t> functions;

Reading data with different types in C++

I want to a program to read strings like:
integer_value 1
double_value 1.0
string_value one
I implement the following functions in order to read these:
void read_val_int(
std::vector<std::string> str_vec,
std::string str,
int& val){
if(str_vec[0]==str) val= std::stoi(str_vec[1]);
}
void read_val_dbl(
std::vector<std::string> str_vec,
std::string str,
double& val){
if(str_vec[0]==str) val= std::stoi(str_vec[1]);
}
void read_val_str(
std::vector<std::string> str_vec,
std::string str,
std::string& val){
if(str_vec[0]==str) val= str_vec[1];
}
str_vec is a vector containing two string values, e.g. {"integer_value","1"}.
str contains a string I want to compare with str_vec[0]
val is an integer, double or string that corresponds to str_vec[1] in case str_vec[0]==str is true.
I use these functions as, e.g. read_val_int(my_str_vec,"integer_value",my_int_val).
My question is: Is there a way of using one single function in order to do this? I have tried using a template but since I need to reference val this seems impossible.
Note: I'm aware of this post but it is in C and seems kinda messy to me. Maybe there is a simpler way to achieve this in C++.
If you are before C++17 and so cannot use std::variant, you can use only one function by using templates.
You declare the function as follows:
template <typename T>
void read_val(const std::string & data, T & val);
Then you specialize it for your three types:
template <>
void read_val<int>(const std::string & data, int & val)
{
val = std::stoi(data);
}
template <>
void read_val<double>(const std::string & data, double & val)
{
val = std::stod(data);
}
template <>
void read_val<std::string>(const std::string & data, std::string & val)
{
val = data;
}
And the job is done, you can use the function for you three types by calling one and only one function: read_val().
You can use it as follows:
std::string data_int("5");
std::string data_double("2.5");
std::string data_string("Hello");
int int_val;
double double_val;
std::string string_val;
read_val(data_int, int_val);
read_val(data_double, double_val);
read_val(data_string, string_val);
std::cout << int_val << std::endl;
std::cout << double_val << std::endl;
std::cout << string_val << std::endl;
As you can see, by the use of template specialization, you can use the same function for different types.
Moreover, it will automatically assure you that an allowed type is passed. Indeed, if you give something else than an int, double or std::string to the function, the compilation will fail because there is no specialization for it.
I hope it helps.
As suggested in Dave's comment, you should check the type of your variable parsing the first element of the vector.
Inside the if-else chain you can what you need with the right type of your variable.
You could also have a single function to return your values using std::variant e then printing values (or do whatever you need) using c++17 std::visit.
It could be something like this:
#include <vector>
#include <string>
#include <variant>
#include <iostream>
using my_variant = std::variant<int, double, std::string>;
my_variant read_val(
const std::vector<std::string> &str_vec)
{
if(str_vec[0]=="integer_value")
{
return std::stoi(str_vec[1]);
}
else if(str_vec[0]=="double_value")
{
return std::stod(str_vec[1]);
}
else if(str_vec[0]=="string_value")
{
return str_vec[1];
}
//notify error in some way, maybe throw
}
void print_variant(const my_variant &v)
{
std::visit([](my_variant &&var)
{
if (std::holds_alternative<int>(var))
std::cout<<"int->"<<std::get<int>(var)<<"\n";
else if (std::holds_alternative<double>(var))
std::cout<<"double->"<<std::get<double>(var)<<"\n";
else if (std::holds_alternative<std::string>(var))
std::cout<<"string->"<<std::get<std::string>(var)<<"\n";
}, v);
}
int main()
{
std::vector<std::string> vec_int {"integer_value", "1"};
std::vector<std::string> vec_dbl {"double_value", "1.5"};
std::vector<std::string> vec_str {"string_value", "str"};
print_variant(read_val(vec_int));
print_variant(read_val(vec_dbl));
print_variant(read_val(vec_str));
return 0;
}

working with expressions: how to minimize runtime construction time

I have two classes, a single expression (SE) and a bundle of two expressions (ME). The bundle is an expression itself, hence it can be an element of another bundle.
struct SE {
SE(char id, char n) : id(id), n(n) {}
size_t size() const { return n; }
char *eval(char *b) const { b[0]=id; return b+1; }
char id, n;
};
template <typename LHS>
struct ME {
ME(const LHS& l, const SE& r) : lhs(l), rhs(r) { }
size_t size() const { return rhs.size(); }
char *eval(char *b) const { *b++='('; b=lhs.eval(b); *b++=','; b=rhs.eval(b); *b++=')'; return b; }
LHS lhs;
SE rhs;
};
The construction of the bundle performs a simple validity check based on the data member n, accessible in ME via the method size. An eval method does some claculations using the data member id. Neither n nor id are known at compile time.
For both classes I override the comma operator, so that it performs the recursive bundling of multiple single expression into a nested bundle.
auto SE::operator,(const SE& r) { return ME<SE>(*this, r); }
auto ME<LHS>::operator,(const SE& r) { return ME<ME<LHS>>(*this, r); }
I want that, after the whole bundle has been constructed, the method eval is triggered on the whole bundle. Example:
SE('a',1); // prints 'a'
SE('a',1), SE('b',1); // prints '(a,b)'
SE('a',1), SE('b',1), SE('c',1); // prints '((a,b),c)'
A possible way to achieve that is to use the destructors of the classes and add a flag is_outer which is updated appropriately during contruction of SE and ME. When any of these class is destructed, if the flag indicates this is the outermost class, then eval is triggered. A full demo is given below.
Testing on godbolt the simple demo function below, it seems to me the compiler generates more code than strictly necessary. Although id and n are not known at compile time, the final type of the expression should be. I would expect the entire construction of the bundle to reduce to just moving a few numbers in the correct place, then check the assertions, but it seems to actually do much more copies.
Is it possible to obtain that more of the contruction part is produced at compile time?
#include <iostream>
#include <cassert>
#include <string>
#include <sstream>
using namespace std;
// forward declaration
template <typename LHS> struct ME;
struct SE {
SE(char id, char n) : id(id), n(n), outer(true) {}
SE(const SE& expr) : id(expr.id), n(expr.n), outer(false) {}
ME<SE> operator,(const SE& r);
size_t size() const { return n; }
char *eval(char *b) const { b[0]=id; return b+1; }
~SE() { if(outer) { char b[20] = {}; char *p=eval(b); *p++='\n'; cout << b; } }
char id, n;
mutable bool outer;
};
template <typename LHS>
struct ME {
ME(const LHS& l, const SE& r)
: lhs(l), rhs(r), outer(true) // tentatively set to true
{ l.outer = r.outer = false; assert(l.size() == r.size()); } // reset flag for arguments
ME(const ME<LHS>& expr)
: lhs(expr.lhs), rhs(expr.rhs), outer(false) {}
size_t size() const { return rhs.size(); }
char *eval(char *b) const { *b++='('; b=lhs.eval(b); *b++=','; b=rhs.eval(b); *b++=')'; return b; }
auto operator,(const SE& r) { return ME<ME<LHS>>(*this, r); }
~ME() { if(outer) { char b[20] = {}; char *p=eval(b); *p++='\n'; cout << b; } }
LHS lhs;
SE rhs;
mutable bool outer;
};
ME<SE> SE::operator,(const SE& r) { return ME<SE>(*this, r); }
void demo(char a, char na, char b, char nb, char c, char nc) {
SE(a, na), SE(b,nb), SE(c,nc); // prints '((a,b),c)'
}
int main() {
demo('a',1,'b',1,'c',1);
return 0;
}
The general pattern you are following is expression templates. Reading up on how others do it will help.
Usually expression templates use CRTP heavily, and do not store copies.
I believe I see bugs due to the copies.
Generally take T&& and store T& or T&&.
Usually expression templates terminate (and execute) when they are assigned to a target; you don't want to that. As C++ lacks move-from-and-destroy, you have to check the "should not be executed" at (nominally) runtime.
Instead of references/values and a bool, you could store pointers and use null as the "don't run" case.
I cannot figure out how to make the work to determine what to run constexpr. It might be possible however.

C++ Math Parser with user-defined function

I want to implement a math parser with user-defined function.
There are several problems to be solved.
For example, int eg(int a,int b){return a+b;} is the function I want to add to the parser.
First: How to store all the functions into a container?
std::map<std::string,boost::any> func_map may be a choose (by func_map["eg"]=eg". However, It's very hard to call the function in this kind of map, for I have to use any_cast<T> to get the real function from the wrapper of boost::any.
Second: How to handle the overloaded function?
It's true that I can distinguish the overloaded functions by the method of typeid, but it's far from a real implementation.
Parsering expressions is not a difficult skill and the hardest part is described above.
muparserx provides an interesting solution for this problem, but I'm finding another method.
I'm not familiar with lambda expressions but may be it's an acceptable way.
Update:
I need something like this:
int eg(int a,int b){ return a+b;}
int eg(int a,int b, string c){return a+b+c.length();}
double eh(string a){return length.size()/double(2);}
int main(){
multimap<string,PACKED_FUNC> func_map;
func_map.insert(make_pair("eg",pack_function<int,int>(eg));
func_map.insert(make_pair("eg",pack_function<int,int,string>(eg));
func_map.insert(make_pair("eh",pack_function<string>(eh));
auto p1=make_tuple(1,2);
int result1=apply("eg",PACK_TUPLE(p1));//result1=3
auto p2=tuple_cat(p1,make_tuple("test"));
int result2=apply("eg",PACK_TUPLE(p2));//result2=7
auto p3=make_tuple("testagain");
double result3=apply("eh",PACK_TUPLE(p3));//result3=4.5
return 0;
}
How to store all the functions into a container?
To store then inside some container, they must be of the same type. The std::function wrapper is a good choice, since this allows you to use even stateful function objects. Since you probably don't want all functions to take the same number of arguments, you need to "extract" the arity of the functions from the static host type system. An easy solution is to use functions that accept a std::vector:
// Arguments type to the function "interface"
using Arguments = std::vector<int> const &;
// the interface
using Function = std::function<int (Arguments)>;
But you don't want your users to write functions that have to unpack their arguments manually, so it's sensible to automate that.
// Base case of packing a function.
// If it's taking a vector and no more
// arguments, then there's nothing left to
// pack.
template<
std::size_t N,
typename Fn>
Function pack(Fn && fn) {
return
[fn = std::forward<decltype(fn)>(fn)]
(Arguments arguments)
{
if (N != arguments.size()) {
throw
std::string{"wrong number of arguments, expected "} +
std::to_string(N) +
std::string{" but got "} +
std::to_string(arguments.size());
}
return fn(arguments);
};
}
The above code handles the easy case: A function that already accepts a vector. For all other functions they need to be wrapped and packed into a newly created function. Doing this one argument a time makes this relatively easy:
// pack a function to a function that takes
// it's arguments from a vector, one argument after
// the other.
template<
std::size_t N,
typename Arg,
typename... Args,
typename Fn>
Function pack(Fn && fn) {
return pack<N+1, Args...>(
[fn = std::forward<decltype(fn)>(fn)]
(Arguments arguments, Args const &... args)
{
return fn(
arguments,
arguments[N],
args...);
});
}
The above only works with (special) functions that already take a vector. For normal functions we need an function to turn them into such special functions:
// transform a function into one that takes its
// arguments from a vector
template<
typename... Args,
typename Fn>
Function pack_function(Fn && fn) {
return pack<0, Args...>(
[fn = std::forward<decltype(fn)>(fn)]
(Arguments arguments, Args const &... args)
{
return fn(args...);
});
}
Using this, you can pack any function up to be the same type:
Function fn =
pack_function<int, int>([] (auto lhs, auto rhs) {return lhs - rhs;});
You can then have them in a map, and call them using some vector, parsed from some input:
int main(int, char**) {
std::map<std::string, Function> operations;
operations ["add"] = pack_function<int, int>(add);
operations ["sub"] = pack_function<int, int>(
[](auto lhs, auto rhs) { return lhs - rhs;});
operations ["sum"] = [] (auto summands) {
int result = 0;
for (auto e : summands) {
result += e;
}
return result;
};
std::string line;
while (std::getline(std::cin, line)) {
std::istringstream command{line};
std::string operation;
command >> operation;
std::vector<int> arguments {
std::istream_iterator<int>{command},
std::istream_iterator<int>{} };
auto function = operations.find(operation);
if (function != operations.end ()) {
std::cout << line << " = ";
try {
std::cout << function->second(arguments);
} catch (std::string const & error) {
std::cout << error;
}
std::cout << std::endl;
}
}
return 0;
}
A live demo of the above code is here.
How to handle the overloaded function? It's true that I can distinguish the overloaded functions by the method of typeid, but it's far from a real implementation.
As you see, you don't need to, if you pack the relevant information into the function. Btw, typeid shouldn't be used for anything but diagnostics, as it's not guaranteed to return different strings with different types.
Now, finally, to handle functions that don't only take a different number of arguments, but also differ in the types of their arguments, you need to unify those types into a single one. That's normally called a "sum type", and very easy to achieve in languages like Haskell:
data Sum = IVal Int | SVal String
-- A value of type Sum is either an Int or a String
In C++ this is a lot harder to achieve, but a simple sketch could look such:
struct Base {
virtual ~Base() = 0;
};
inline Base::~Base() {}
template<typename Target>
struct Storage : public Base {
Target value;
};
struct Any {
std::unique_ptr<Base const> value;
template<typename Target>
Target const & as(void) const {
return
dynamic_cast<Storage<Target> const &>(*value).value;
}
};
template<typename Target>
auto make_any(Target && value) {
return Any{std::make_unique<Storage<Target>>(value)};
}
But this is only a rough sketch, since there's boost::any which should work perfectly for this case. Note that the above and also boost::any are not quite like a real sum type (they can be any type, not just one from a given selection), but that shouldn't matter in your case.
I hope this gets you started :)
Since you had problems adding multi type support I expanded a bit on the above sketch and got it working. The code is far from being production ready, though: I'm throwing strings around and don't talk to me about perfect forwarding :D
The main change to the above Any class is the use of a shared pointer instead of a unique one. This is only because it saved me from writing copy and move constructors and assignment operators.
Apart from that I added a member function to be able to print an Any value to a stream and added the respective operator:
struct Base {
virtual ~Base() = 0;
virtual void print_to(std::ostream &) const = 0;
};
inline Base::~Base() {}
template<typename Target>
struct Storage : public Base {
Target value;
Storage (Target t) // screw perfect forwarding :D
: value(std::forward<Target>(t)) {}
void print_to(std::ostream & stream) const {
stream << value;
}
};
struct Any {
std::shared_ptr<Base const> value;
template<typename Target>
Target const & as(void) const {
return
dynamic_cast<Storage<Target> const &>(*value).value;
}
template<typename T>
operator T const &(void) const {
return as<T>();
}
friend std::ostream & operator<<(std::ostream& stream, Any const & thing) {
thing.value->print_to(stream);
return stream;
}
};
template<typename Target>
Any make_any(Target && value) {
return Any{std::make_shared<Storage<typename std::remove_reference<Target>::type> const>(std::forward<Target>(value))};
}
I also wrote a small "parsing" function which shows how to turn a raw literal into an Any value containing (in this case) either an integer, a double or a string value:
Any parse_literal(std::string const & literal) {
try {
std::size_t next;
auto integer = std::stoi(literal, & next);
if (next == literal.size()) {
return make_any (integer);
}
auto floating = std::stod(literal, & next);
if (next == literal. size()) {
return make_any (floating);
}
} catch (std::invalid_argument const &) {}
// not very sensible, string literals should better be
// enclosed in some form of quotes, but that's the
// job of the parser
return make_any<std:: string> (std::string{literal});
}
std::istream & operator>>(std::istream & stream, Any & thing) {
std::string raw;
if (stream >> raw) {
thing = parse_literal (raw);
}
return stream;
}
By also providing operator>> it's possible to keep using istream_iterators for input.
The packing functions (or more precisely the functions returned by them) are also modified: When passing an element from the arguments vector to the next function, an conversion from Any to the respective argument type is performed. This may also fail, in which case a std::bad_cast is caught and an informative message rethrown. The innermost function (the lambda created inside pack_function) wraps its result into an make_any call.
add 5 4 = 9
sub 3 2 = 1
add 1 2 3 = wrong number of arguments, expected 2 but got 3
add 4 = wrong number of arguments, expected 2 but got 1
sum 1 2 3 4 = 10
sum = 0
sub 3 1.5 = argument 1 has wrong type
addf 3 3.4 = argument 0 has wrong type
addf 3.0 3.4 = 6.4
hi Pete = Hello Pete, how are you?
An example similar to the previous one can be found here. I need to add that this Any type doesn't support implicit type conversions, so when you have an Any with an int stored, you cannot pass that to an function expecting a double. Though this can be implemented (by manually providing a lot of conversion rules).
But I also saw your update, so I took that code and applied the necessary modifications to run with my presented solution:
Any apply (multimap<string, Function> const & map, string const & name, Arguments arguments) {
auto range = map.equal_range(name);
for (auto function = range.first;
function != range.second;
++function) {
try {
return (function->second)(arguments);
} catch (string const &) {}
}
throw string {" no such function "};
}
int eg(int a,int b){ return a+b;}
int eg(int a,int b, string c){return a+b+c.length();}
double eh(string a){return a.size()/double(2);}
int main(){
multimap<string, Function> func_map;
func_map.insert(make_pair(
"eg",pack_function<int,int>(
static_cast<int(*)(int, int)>(&eg))));
func_map.insert(make_pair(
"eg",pack_function<int,int,string>(
static_cast<int (*)(int, int, string)>(&eg))));
func_map.insert(make_pair(
"eh",pack_function<string>(eh)));
// auto p1=make_tuple(1,2);
// if you want tuples, just write a
// function to covert them to a vector
// of Any.
Arguments p1 =
{make_any (1), make_any (2)};
int result1 =
apply(func_map, "eg", p1).as<int>();
vector<Any> p2{p1};
p2.push_back(make_any<string> ("test"));
int result2 =
apply(func_map, "eg", p2).as<int>();
Arguments p3 = {make_any<string>("testagain")};
double result3 =
apply(func_map, "eh", p3).as<double>();
cout << result1 << endl;
cout << result2 << endl;
cout << result3 << endl;
return 0;
}
It doesn't use tuples, but you could write a (template recursive) function to access each element of a tuple, wrap it into an Any and pack it inside a vector.
Also I'm not sure why the implicit conversion from Any doesn't work when initialising the result variables.
Hm, converting it to use boost::any shouldn't be that difficult. First, the make_any would just use boost::any's constructor:
template<typename T>
boost::any make_any(T&& value) {
return boost::any{std::forward<T>(value)};
}
In the pack function, the only thing that I'd guess needs to be changed is the "extraction" of the correct type from the current element in the arguments vector. Currently this is as simple as arguments.at(N), relying on implicit conversion to the required type. Since boost::any doesn't support implicit conversion, you need to use boost::any_cast to get to the underlying value:
template<
std::size_t N,
typename Arg,
typename... Args,
typename Fn>
Function pack(Fn && fn) {
return pack<N+1, Args...>(
[fn = std::forward<decltype(fn)>(fn)]
(Arguments arguments, Args const &... args)
{
try {
return fn(
arguments,
boost::any_cast<Arg>(arguments.at(N)),
args...);
} catch (boost::bad_any_cast const &) { // throws different type of exception
throw std::string{"argument "} + std::to_string (N) +
std::string{" has wrong type "};
}
});
}
And of course, if you use it like in the example you provided you also need to use boost::any_cast to access the result value.
This should (in theory) do it, eventually you need to add some std::remove_reference "magic" to the template parameter of the boost::any_cast calls, but I doubt that this is neccessary.
(typename std::remove_reference<T>::type instead of just T)
Though I currently cannot test any of the above.