Pass a function of n arguments as function of n-x arguments - c++

This is a very basic question and I'm sure this was answered before, but I don't know what to search for.
Stated I have a function that integrates a mathematical function:
double integrator(double (*func_to_integrate)(double,double));
But my function to integrate is of a type that allows me to manipulate more than two parameters, for example:
double func_to_integrate(double mu, double w0, double x, double y);
So that I can loop over different values of mu and w0 and compare the results of integration.
How can I pass a function like func_to_integrate to integrator?
Greetings
Edit: As alain pointed out in the comments this is partly a duplicate of: How can currying be done in C++?
Is there an elegant solution doing a currying operation on a function pointer?

Given you are able to change the signature of the integrator function, there are several solutions. The basic two directions are
use a general template parameter instead of the function pointer (--where the caller has to be aware of the correct signature to pass), or
use std::function<double(double, double)> as the function argument.
Both alternatives allow you to pass general function objects (functors, lambdas, a std::bind-object, etc.). I'd go with alternative 1. as it usually gives a better performance.
Then you can easily set up a lambda:
double mu = 1.0;
double w0 = 1.0;
auto f = [mu, w0] (double x, double y) { return func_to_integrate(mu, w0, x, y); };
and pass f to your (adusted) integrator routine.
Here is further an alternative if you cannot change the function signature -- as it is often the case for third-party libraries.
I first thought there is no solution in this case, as you can't bind a general functor to a function pointer. But then I encountered the nice idea in this answer (which I slightly adjusted): encode everything in terms of a static std::function variable, then use a static function to call this std::function object. As the static function is just syntactic sugar for a global function, it is possible to set up a function pointer to it:
template <typename Res, typename... Args>
struct function_ptr_helper
{
public:
template<typename function_type>
static auto bind(function_type&& f) { func = std::forward<function_type>(f); }
static auto invoke(Args... args) { return func(args...); }
static auto* ptr() { return &invoke; }
private:
static std::function<Res(Args ...)> func;
};
template <typename Res, typename... Args>
std::function<Res(Args ...)> function_ptr_helper<Res, Args...>::func;
template <typename Res, typename ... Args>
auto* get_function_ptr(std::function<Res(Args...)> f)
{
using type = function_ptr_helper<Res, Args...>;
type::bind(std::move(f));
return type::ptr();
}
DEMO
You can use it as
double mu = 1.0;
double w0 = 1.0;
std::function<double(double, double)> f
= [mu, w0] (double x, double y) { return func_to_integrate(mu, w0, x, y); };
integrator(get_function_ptr(f));
Be aware, however, that you are dealing with global variables here. This often works, but sometimes might lead to subtle errors (for example when you call get_function_ptr more than once in a single expression).

How can I pass a function like func_to_integrate to integrator?
Seems very easy to fix. Just add two more arguments to your pointer function signature.
double integrator(double (*func_to_integrate)(double,double,double,double));

As previous comments point out the most elegant solution would be using bind and or lambda. A nice solution would be an adapter design pattern class wrapper, where mu and w0 become class members.
class IntegratorAdaptor {
private:
double _mu, double _w0;
public:
IntegratorAdapter(double arg_mu, double arg_w0)
: _mu(arg_mu), _w0(arg_w0) { }
double twoArgIntegrator( double x, double y )
{ return func_to_intergrate( _mu, _w0, x, y ); }
};
Construction of this class is very low overhead, so I made the members immutable. I didn't come up with very good names for the class and functions, you should put more thought into those names than I did.

Most answers I've seen for this kind of question rely on std::function and/or C++ templates. I wanted to share an alternate solution which may be less general, but to me is simpler. It doesn't use std::function or templates---in fact, it doesn't use any libraries at all.
The idea is that instead of passing around a function pointer, you pass around an object that implements a particular 'interface'. In this example,
double integrator(double (*func_to_integrate)(double,double))
becomes
double integrator(Integratable func_to_integrate)
where Integratable is an 'interface' (abstract base class) defined as
class Integratable {
public:
virtual double compute(double x, double y) = 0; // pure virtual function
}
We can then make func_to_integrate into an instance of this class, with extra members for the additional parameters:
class SomeClassName : public Integratable {
public:
double compute(double x, double y);
double mu;
double w0;
}
SomeClassName func_to_integrate;
To test several values of mu and w0 in a loop:
for(double mu : mus) {
for(double w0 : w0s) {
func_to_integrate.mu = mu;
func_to_integrate.w0 = w0;
integrator(func_to_integrate);
}
}
Of course, we have to modify integrator so that instead of calling a function pointer, it calls the compute() method on the object passed to it, but this is trivial (assuming you can change the signature of integrator, which is probably required for any possible solution to this problem).
I like this solution because it avoids some of C++'s more heavyweight features and libraries. However, it certainly is less general than many of the other solutions that are often suggested for partial application in C++. For OP I believe this solution is an elegant fit for the given use case.

Related

Using Boost bisection when the function relies on a class attribute and has additional arguments

I am trying to use the Boost bisection method described here.
I have seen a couple of examples of how to get this to work, e.g. How to use boost bisection?, but I don't understand how to apply these to my particular set-up.
Here is a sketch of some code that illustrates what I am trying to do.
class Model {
double b;
double root;
public:
double func(double x, double c);
void solve(void);
};
double Model::func(double x, double c) {
return (x*x*x + (b*x) + c);
}
void Model::solve(void) {
double c;
b = 2.;
c = 1.;
// root = bisect(func(), from, to, ...);
// where the first argument to func() is what we want to find the root over
// and the second argument to func() is c
}
int main(void) {
Model model;
model.solve();
}
The member function solve() needs to find the root of the member function func(). func() has two important features:
It relies on the class attribute b
It has a second argument c that is determined in solve(). I want to hold this second argument fixed when finding the root
How would I implement the Boost bisection method in this context? This answer seems to suggest that boost::bind might solve part of the problem but I don't understand enough of it to know how to apply it to my problem.

Create a function from another one

more than a general case, I have a very specific example in mind : in GSL (GNU Scientific Library), the main function type used (in order to perform integration, root finding,...) is gsl_function , which have an attribute function whose type is double(*)(double, void *)
Say I want to create a gsl_function from double a_squared(double a) {return a*a};. a__squared 's type is double(*)(double) I would like to create a convert function taking in argument (double(*)(double) f) and returning an object of type double(*)(double, void *) which would satisfy convert(f)(double a, NULL) == f(a)
But after some research, it seems like I can't define another function in my convert function. How to proceed ?
The need to pass a raw function pointer to the GSL API limits your options considerably - you can't use anything based on std::function because there's no way to obtain a function pointer from a std::function (and this rules out lambdas using captures, which would have offered a neat solution).
Given these constraints, here's a possible solution making use of a static wrapper class. You could just as well have put the contents of this class in a namespace, but using the class at least gives some semblance of encapsulation.
typedef double gsl_function_type(double, void*); // typedef to make things a bit more readable...
// static class to wrap single-parameter function in GSL-compatible interface
// this really just serves as a namespace - there are no non-static members,
// but using a class lets us keep the details private
class Convert
{
Convert() = delete; // don't allow construction of this class
// pointer to the function to be invoked
static double (*m_target)(double);
// this is the function we'll actually pass to GSL - it has the required signature
static double target(double x, void*) {
return m_target(x); // invoke the currently wrapped function
}
public:
// here's your "convert" function
static gsl_function_type* convert(double (*fn)(double)) {
m_target = fn;
return &target;
}
};
There's a live example here: http://coliru.stacked-crooked.com/a/8accb5db47a0c51d
You're trapped by gsl's (poor) design choice of using C (instead of C++) to provide a C-style function pointer. Thus, you cannot use (C++ style) function-objects (functor), but must provide the pointer to a real function and one cannot generate a function in the same way one can genarate functors.
(Not recommended) You can use a global variable to store the actual function (a_squared) and then define a particular gsl_function that actually calls that global variable:
// from some gsl header:
extern "C" {
typedef double gsl_function(double, void*);
// calls func(arg,data_passed_to_func)
double gsl_api_function(gsl_function*func, void*data_passed_to_func);
}
// in your source code
double(*target_func)(double); // global variable can be hidden in some namespace
extern "C" {
double funtion_calling_target(double, void*)
}
double funtion_calling_target(double arg, void*)
{
return target_func(arg);
}
bool test(double x, double(*func)(double))
{
target_func = func;
return x < gsl_api_function(function_calling_target,0);
}
(hiding target_func as static member of some class as in atkins's answer still requires a global variable). This works, but is poor, since 1) this mechanism requires a global variable and 2) only allows one target function to be used a any time (which may be hard to ensure).
(Recommended) However, you can define a special function that takes another function pointer as argument and passes it as data element. This was in fact the idea behind the design of gsl_function: the void* can point to any auxiliary data that may be required by the function. Such data can be another function.
// your header
extern "C" {
double function_of_double(double, void*);
}
inline double function_of_double(double arg, void*func)
{
typedef double(*func_of_double)(double);
return reinterpret_cast<func_of_double>(func)(arg);
}
// your application
bool test(double x, double(*func)(double))
{
return x < gsl_api_function(function_of_double, (void*)(func));
}
This does not require a global variable and works with as many different simultaneous functions as you want. Of course, here you are messing around with void*, the very thing that every sensible C++ programmer abhors, but then you're using a horrible C library which is based on void* manipulations.
Thought I would add my lambda-based attempts at this.
It works fine in principle:
// function we want to pass to GSL
double a_squared(double a) { return a*a; }
typedef double gsl_function_type(double, void*); // convenient typedef
// lambda wrapping a_squared in the required interface: we can pass f directly to GSL
gsl_function_type* f = [](double x, void*) { return a_squared(x); };
But we'd really like to write a method to apply this to any given function. Something like this:
gsl_function_type* convert(double (*fn)(double))
{
// The lambda has to capture the function pointer, fn.
return [fn](double x, void*) { return fn(x); };
}
However, the lambda now has to capture the pointer fn, because fn has automatic storage duration (in contrast to the static function a_squared in the first example). This doesn't compile because a lambda which uses a capture cannot be converted to a simple function pointer, as required by the return value of our function. In order to be able to return this lambda we'd have to use a std::function, but there's no way to get a raw function pointer from that, so it's no use here.
So the only way I've managed to get this to work is by using a preprocessor macro:
#define convert(f) [](double x, void*) { return f(x); }
This then lets me write something like this:
#include <iostream>
using namespace std;
typedef double gsl_function_type(double, void*); // convenient typedef
// example GSL function call
double some_gsl_function(gsl_function_type* function)
{
return function(5.0, nullptr);
}
// function we want to pass to GSL
double a_squared(double a) { return a*a; }
// macro to define an inline lambda wrapping f(double) in GSL signature
#define convert(f) [](double x, void*) { return f(x); }
int main()
{
cout << some_gsl_function(convert(a_squared)) << endl;
}
Personally, as much as I dislike using macros, I would prefer this over my other suggestion. In particular, it solves the problems #Walter pointed out with that idea.
Previous answers - including the accepted one - seem correct, but they are not general enough in case you need to convert other types of function to gsl_function (including member functions for example). So, let me add a more powerful alternative.
If you use the wrapper described here, then you can convert any C++ lambdas to gsl_functions in two simple lines
// Example
gsl_function_pp Fp([&](double x){return a_squared(x);});
gsl_function *F = static_cast<gsl_function*>(&Fp);
This solves any related conversion problems. You can also use std::bind and any std::functions.

Cache Optimization and Polymorphism

Suppose I have a calculator class that implements the Strategy Pattern using std::function objects as follows (see Scott Meyers, Effective C++: 55 Specific Ways to Improve Your Programs and Designs):
class Calculator
{
public:
...
std::vector<double> Calculate(double x, double y)
{
std::vector<double> res;
for(const Function& f : functions)
res.push_back(f(x,y));
return res;
}
private:
std::vector<Function> functions;
};
where
typedef std::function<double(double,double)> Function;
Here is the problem I am facing: suppose functions f and g, both of type Function, perform expensive and identical calculations internally to get the final result. In order to improve efficiency, one could wrap all the common data in a struct, compute it once and provide to them as an argument. However, this design has several flaws. For example, this would cause a change in the signature of Function, which can result in unnecessary arguments being passed to some function implementations. Moreover, these common and internal data are no longer hidden from other components in the code, which can harm code simplicity.
I would like to discuss the following optimization strategy: implement a class CacheFG that:
Define a Update method that calculates its internal data with a given pair of doubles x and y; and
Define a Check method to determine if its current internal data was calculated with a given pair of doubles x and y.
What one could do then is to make f and g to share a common instance of the class CacheFG, which could be done using the std::shared_ptr construct. So, below would be the creation of f and g functions using auxiliary functions f_aux and g_aux.
double f_aux(double x, double y, const std::shared_ptr<CacheFG>& cache)
{
if(not cache->Check(x,y))
cache->Update(x,y);
...
}
std::shared_ptr<CacheFG> cache;
Function f = std::bind(f_aux, _1, _2, cache);
Function g = std::bind(g_aux, _1, _2, cache);
My questions are: (1) is this a safe approach for optimization? (2) is there a better approach for solving this problem?
Edit: After a few answers, I found out that my intention here is to implement a memoization technique in C++. I remark that only the last calculated state is enough for my purposes.
Thanks to DeadMG, I will now write here just an improvement over his approach. His idea consists of using a memoization technique with variadic templates. I just offer a slight modification, where I use the construct std::decay<Args>::type to ensure the definition of a tuple with non-reference types only. Otherwise, functions with const-reference arguments would cause compilation errors.
template<typename Ret, typename... Args>
std::function<Ret(Args...)> MemoizeLast(std::function<Ret(Args...)> f)
{
std::tuple<typename std::decay<Args>::type...> cache;
Ret result = Ret();
return [=](Args... args) mutable -> Ret
{
if(std::tie(args...) == cache)
return Ret(result);
cache = std::make_tuple(args...);
return result = f(args...);
};
}
In order to prevent the move of result, a copy of it is returned (return Ret(result)) when the provided args is the one cached.
Why create your own class? There's no need for you to fail to re-create the interface of unordered_map. This functionality can be added as a re-usable algorithm based on std::function and std::unordered_map. It's been a while since I worked with variadic templates, but I hope you get the idea.
template<typename Ret, typename... Args>
std::function<Ret(Args...)> memoize(std::function<Ret(Args...)> t) {
std::unordered_map<std::tuple<Args...>, Ret> cache;
return [=](Args... a) mutable -> Ret {
if (cache.find(std::make_tuple(a...)) != cache.end())
return cache[std::make_tuple(a...)];
else
return cache[std::make_tuple(a...)] = t(a...);
};
}
I don't recall, offhand, whether std::hash natively supports tuples. If not, you might need to add it, or use std::map which does natively support them.
Edit: Hmm, I didn't notice that you wanted to share the cache. Well, this shouldn't be too difficult a problem, just stick an unordered_map member in Calculator and pass it in by reference, but the semantics of doing so seem a bit... odd.
Edit again: Just the most recent value? Even simpler.
template<typename Ret, typename... Args>
std::function<Ret(Args...)> memoize_last(std::function<Ret(Args...)> t) {
std::tuple<Args...> cache;
Ret result;
return [=](Args... a) mutable -> Ret {
if (std::tie(a...) == cache)
return result;
cache = std::make_tuple(a...);
return result = t(a...);
};
}
If you want to share between several Functions, then the alteration is the same- just declare it in the class and pass in as reference.
Before optimizing - measure. Then if you really perform many calculations with same value - then create this cache object. I'd like to hide cache checking and updating in CacheFG::get(x, y) and use it like const auto value = cache->get(x,y).

Very basic question about argument with signature void *data

This is very likely an extremely basic question - sorry about that.
I have written an interface in C++ which is powered by a C engine. One of the C-engine functions has the following signature:
static int f(double t, double *y, double *ydot, void *data)
The *data thingy is to pass user data to an ODE solver. Now, in C I would simply create an struct, initialize it with my data, and pass it around. In C++ I want to create a class containing the user data, and pass it as I previously passed the struct. This can be done, as structs are classes.
However, when I try to do it, the following happens:
int.cpp:25: error: no matching function for call to ‘UserData::UserData()’
int.cpp:13: note: candidates are: UserData::UserData(double)
int.cpp:5: note: UserData::UserData(const UserData&)
int.cpp:28: error: ‘void*’ is not a pointer-to-object type
int.cpp:29: error: ‘void*’ is not a pointer-to-object type
My questions are the following:
What does the void *data notation mean?
Why is it complaining that I don't have a constructor with the appropriate signature?
Obviously I am very much a rookie, so I'm sorry if this is very obvious, but I don't even know what terms to use to google the problem (in addition to googling the error itself).
Thanks!
Edit:
I apologize for the vagueness of the previous question. Also, I solved the problem and it was a very stupid mistake.
I had a class containing parameters:
class Data{
// an interface to get parameters
};
and I needed to call a C function with the signature
static int f(double t, ...., void *user_data)
I mistakenly did this:
static int f(double t, ...., void *user_data){
Data *data = (Data*) data; /* this is the stupid mistake */
}
When I meant to do this (now it works):
static int f(double t, ...., void *user_data){
Data *data = (Data*) user_data; /* this is the correction */
}
Thank you all - and I appreciate indicating the correct meaning of void *data.
void *data
means a pointer to any address. It is a non-typesafe way of passing data of arbitrary type. It is a common pattern in C to implement what would be done with a function object in C++. The data parameter is probably not actually used by your ODE solver, but by a callback that you are providing. You and the callback need to know the what data points to, the ODE solver doesn't. The solver just passes the address to the callback function.
As simple example, suppose the library had a function to find the root of a function in a single variable
typedef double (*valuation_function) (double x, void * params);
double find_root(valuation_function fn, double lower, double upper, void* params);
The params function gives you the ability to write a parameterized function. Suppose you wanted to find the root of a line.
struct Line {
double slope;
double intercept;
public:
Line(double s, double i) : slope(s), intercept(i) {}
};
double a_line(double x, void *params) {
Line* line = (Line *)params;
return line->slope * x + line->intercept;
}
You could then call the function find_root for any line.
Line fortyFive(1.0, 0.0);
find_root(a_line, fortyFive);
You can look at the gsl library for more examples.

container of mixed types in C++ (similar to nsdictionary)

What I would like to do (in C++) is create a 'Parameter' data type which has a value, min, and max. I would then like to create a container for these types.
E.g. I have the following code:
template <typename T>
class ParamT {
public:
ParamT() {
}
ParamT(T _value):value(_value) {
}
ParamT(T _value, T _vmin, T _vmax):value(_value), vmin(_vmin), vmax(_vmax) {
}
void setup(T vmin, T vmax) {
this->vmin = vmin;
this->vmax = vmax;
}
void setup(T value, T vmin, T vmax) {
setup(vmin, vmax);
setValue(value);
}
T operator=(const T & value) {
setValue(value);
}
void setValue(T v) {
value = v;
}
T getValue() {
return value;
}
operator T() {
return getValue();
}
protected:
T value;
T vmin;
T vmax;
};
typedef ParamT<int> Int;
typedef ParamT<float> Float;
typedef ParamT<bool> Bool;
In an ideal world my Api would be something like:
std::map<string, Param> params;
params["speed"] = PFloat(3.0f, 2.1f, 5.0f);
params["id"] = PInt(0, 1, 5);
or
params["speed"].setup(3.0f, 2.1f, 5.0f);
params["id"].setup(0, 1, 5);
and writing to them:
params["speed"] = 4.2f;
params["id"] = 1;
or
params["speed"].setValue(4.2f);
params["id].setValue(1);
and reading:
float speed = params["speed"];
int id = params["id"];
or
float speed = params["speed"].getValue();
int id = params["id"].getValue();
Of course in the code above, ParamT has no base class so I cannot create a map. But even if I create a base class for it which ParamT extends, I obviously cannot have different getValues() which return different types. I thought about many solutions, including setValueI(int i), setValuef(float f), int getValueI(), float getValueF(), or a map for ints, a map for floats etc. But all seem very unclean. Is it possible in C++ to implement the above API?
At the moment I am only concerned with simple types like int, float, bool etc. But I would like to extend this to vectors (my own) and potentially more.
It's a tough concept to implement in C++, as you're seeing. I'm always a proponent of using the Boost library, which has already solved it for you. You can typedef the complex boost variant template class to something more usable in your specific domain, so
typedef boost::variant< int, float, bool > ParamT;
class Param
{
public:
// initialize the variants
Param(ParamT min, ParamT max, ParamT value)
: m_Min(min), m_Max(max), m_Value(value) {}
// example accessor
template<typename OutT>
const ParamT& value()
{
return boost::get<OutT>(m_Value);
}
// other accessors for min, max ...
private:
ParamT m_Min, m_Value, m_Max;
};
Param speed(-10.0f, 10.0f, 0.0f);
float speedValue = speed.value<float>();
Now, to add another type to your variant (eg, long, std::string, whatever) you can just modify the typedef of ParamT; The catch, here, is that the burden of checking the types is on you - it'll throw an exception if you store a float and try to receive an int, but there's no compile-time safety.
If you want to get really crazy, you can implement an overloaded cast operator on a proxy object....
class ProxyValue
{
public:
ProxyValue(ParamT& value) : m_Value(value) {}
template<typename ValueT>
operator ValueT()
{
return boost::get<ValueT>(m_Value);
}
private:
ParamT& m_Value;
};
You'd return this from a non-templated value() function in Param, instead of the variant itself. Now you can assign a value without the template call..
Param speed(-10.0f, 0, 10);
float speedValue = speed.value();
Though fair warning, you're stepping into meta-programming hell here. Here thar be dragons. And as always, this is not a complete solution, just a pointer. YMMV.
Heres a roughly working version showing how to use it, and the failures that are easy to hit.
Ok, I'm bored at work (just waiting for something to compile), so here's another solution. Just have one type Param that stores three Values. Those values can by dynamically typed and can store ints and floats (and anything else you want them to).
class Value
{
private:
union
{
int i,
float f
} val;
DataTypeCode dtc;
public
Value() : val.i(0), dtc(INT) {}
Value(int i) : val.i(i), dtc(INT) {}
Value(float f) : val.f(f), dtc(FLOAT) {}
Value& operator=(int i)
{
val.i=i;
dtc=INT;
return *this;
}
Value& operator=(float f)
{
val.f=f;
dtc=FLOAT;
return *this;
}
operator int()
{
switch (dtc)
{
case INT: return val.i;
case FLOAT: return (int)val.f;
}
return 0;
}
operator float()
{
switch (dtc)
{
case INT: return (float)val.i;
case FLOAT: return val.f;
}
return 0;
}
}
class Param
{
private:
Value value, min, max
public:
Param(Value value, Value min, Value max) : value(value), min(min), max(max) {}
}
note, this still requires that DataTypeCode enum that I have in my other answer.
Now to access it, all you have to do is this:
std::map<string:Param> Params;
Params["speed"]=Param(1.4,0.1,5.6)
float speed=Params["speed"]
the cast operators along with the overloaded constructors and operator= functions will automatically convert among the types for you.
You can use either boost::any (to be able to store any type) or boost::variant (to store any type from a fixed set of prespecified types); however, the boost::program_options library largely already does what you want. I would strongly advise that you use boost::program_options rather than rolling this library yourself. I should point out that there is a major downside to what you are doing; you are validating types manually at runtime, which makes it easy for various errors to slip through. I strongly recommend using protocol buffers as a configuration language, as you get stronger type-checking that way.
A question I have about your design is why do you need to support all these value types? Performance, type safety, numeric accuracy, or simplicity/ease of use? It's going to be tough to get your interface to support all of these.
One simple way to solve the question, as you posed it, would be to pick a single numeric type that supports all the values you are interested in. In general, a double should suffice. It will be obvious to users what is going on under the hood, and you don't need to do anything weird with your implementation.
If you need perfect storage, you could implement your own numeric type that can do conversions (implicit or explicit) to various numeric types, and maintain perfect storage if you convert to/from the same type. If you're really concerned about perfect storage, you could also make it throw if you try to do a conversion back to the wrong type. This is like a strongly typed union. I believe the boost library has a type like this. Edit: Nicholas M T Elliott's answer already mentions this - boost variant.
If you like the even-more-explicit interface that you have here, with your GetValueAsInt/SetValueAsInt interface, you can still make it slightly simpler. Combine the setters, since C++ supports function overloading for parameters: void SetValue(int value) void SetValue(float value). C++ does not support function overloading for return types, though, so you cannot combine the getters.
Edit:
No matter which of these you pick, you're going to have a problem making it generic, or adding new types to it later. You must modify the property map's value type every time you want to support an new class.
The simplest way around this in C++ is to use a void* as your value type, and do casts to convert it to and from your target type. Your library could provide a template wrapper to do this cast, and throw if the cast fails.
This is similar to using "object" in Java/C#
Edit:
As Michael Aaron Safyan suggested, you could use boost::any.
In the end, you need to think about this: must your design include property dictionaries? If it doesn't have to have it, then you could benefit from the compiler's static analysis if you abandon this idea. Any behavior you push off to runtime will cause bugs that you won't find at compile time. It does make it faster to get the code running, but it makes your runtime error handling harder, and can hurt perf.
Well, it's easy to make a container store just about anything. As you said, you could make a common base class and have the map just store a pointer to that. The hard part is knowing what data type they are when you're retrieving them and using it. I have something like this in my main project where I'm mixing compile-time type determined c++ code and run-time type determined code from another language. So I embed into the class it's datatype code so that I can do a switch() statement on it. You could have something like this:
enum DataTypeCode
{
UNKNOWN,
INT,
FLOAT
};
template <class DataType>
DataTypeCode GetDataTypeCode()
{
return UNKNOWN;
}
template <>
DataTypeCode GetDataTypeCode<int>()
{
return INT;
}
template <>
DataTypeCode GetDataTypeCodE<float>(
{
return FLOAT;
}
class BaseParam
{
public:
virtual ~BaseParam() {}
virtual DataTypeCode GetDataTypeCode()=0;
};
template <class DataType>
class Param : public BaseParam
{
public:
DataTypeCode GetDataTypeCode()
{
return ::GetDataTypeCode<DataType>();
}
}
and you have to store it as a pointer to take care of polymorphism:
std::map<string,BaseParam*> Params
Params["speed"]=new Param<float>(...)
BaseParam* pMyParam=Params["speed"];
switch (pMyParam->GetDataTypeCode())
{
case INT:
//dosomething with int types
case FLOAT:
//dosomething with float types
}
It's not pretty, but it'll get the job done. Normally, I'll end up wrapping the std::map<string, BaseParam*> inside of another class to hide the fact that it's storing a pointers. I like to make my APIs hide the use of pointers as much as possible, it makes it easier for the junior programmers on my team to deal with it.