In my 32-bit VS2015 application, I have a templated function that accesses functions of a library (BTK). Depending on the type of this function, a specific overload of a function of this library is called.
This works fine, but recently I'm using this same code and library (same binaries and code) in another (also VS2015 32-bit) application, and it segfaults/access violation in the destructor of shared_ptr. To be precise, it crashes at the (interlocked) decrement of the use count.
void _Decref()
{ // decrement use count
if (_MT_DECR(_Uses) == 0) // BOOM
{ // destroy managed resource, decrement weak reference count
_Destroy();
_Decwref();
}
}
Now comes the interesting part, when I replace my templated function with a non-templated version, it works fine..
So, if I replace this:
template<class T>
bool SetParameters(const std::string& group, const std::string& param, const std::vector<T>& values, const std::vector<uint8_t>& dims)
{
btk::MetaData::Pointer pParam = GetBtkMetaData(group, param);
if (!pParam)
{
pParam = AddBtkMetaData(group, param);
}
if (!pParam->HasInfo())
{
pParam->SetInfo(btk::MetaDataInfo::New(dims, values));
}
else pParam->GetInfo()->SetValues(dims, values);
return true;
}
with this:
bool C3DFile::SetParameters(const std::string& group, const std::string& param, const std::vector<int16_t>& values, const std::vector<uint8_t>& dims)
{
btk::MetaData::Pointer pParam = GetBtkMetaData(group, param);
if (!pParam)
{
pParam = AddBtkMetaData(group, param);
}
if (!pParam->HasInfo())
{
pParam->SetInfo(btk::MetaDataInfo::New(dims, values));
}
else pParam->GetInfo()->SetValues(dims, values);
return true;
}
It works fine... Apparantly, the template-instantiation has some effect on the shared pointers. I have three questions:
What kind of effect could templates have on this? I can imagine that the code instantiation could have some effect, but I'm not sure.
Why would the templated version work, with the same binaries etc, in one 32-bit VS2015 app, but not in the other? (Where I need to resort to non-templated functions)
Which compiler/linker options could be relevant? I checked the compiler and linker options, but couldn't find a relevant difference.
Any help would be appreciated.
Ben
What kind of effect could templates have on this? I can imagine that the code instantiation could have some effect, but I'm not sure.
ADL: the template method will use ADL to find the dependent methods (in your case btk::MetaDataInfo::New(dims, values)), whereas the non template only considers visible declarations, so the possible difference.
Example:
struct A{};
void fooT(const void*) { std::cout << "void*\n"; }
template <typename T> void barT(const T* p) { fooT(p); }
void fooT(const A*) { std::cout << "A*\n"; }
void foo(const void*) { std::cout << "void*\n"; }
void bar(const A* p) { foo(p); }
void foo(const A*) { std::cout << "A*\n"; }
int main()
{
A a{};
barT(&a); // fooT(const A*) -> A*
bar(&a); // foo(const void*) -> void*
}
Demo
Related
I have been thinking about this, and I think I read about it somewhere, but I can no longer find more information about this.
Just for theoretical, not pratical purposes, is it possible, feasible, and/or practical to generate a single template instance, that is able to handle all instances of such a template? Has any compiler been able to do this?
For instance, consider this class template...
template<typename T>
class UselessCalculator {
private:
T result;
public:
UselessCalculator() : result(0) {}
UselessCalculator &operator=(T what) {
this->result = what;
return *this;
}
UselessCalculator &operator+=(T what) {
this->result += what;
return *this;
}
UselessCalculator &operator-=(T what) {
this->result -= what;
return *this;
}
UselessCalculator &operator*=(T what) {
this->result *= what;
return *this;
}
UselessCalculator &operator/=(T what) {
this->result /= what;
return *this;
}
};
For any T, UselessCalculator has sort of a list of requireements for it to be used as a template argument for it, much like concepts. In this case, the requirements are:
Being initializable by means of T(0).
Have overloaded operator+=(T, T).
Have overloaded operator-=(T, T).
Have overloaded operator*=(T, T).
Have overloaded operator/=(T, T).
Now, according to this stupid "single instance fits all" idea, how would this be implemented? I thought that the following C code may illustrate a posibility...
struct UselessCalculatorTemplateVirtualTable {
struct someFunkyImplementationOfStdTypeInfo *type;
void (*constructInt)(void*, int);
void (*copyConstruct)(void*, const void*);
void (*moveConstruct)(void*, void*);
void (*destruct)(void*);
void (*operatorAddAssign)(void*, const void*);
void (*operatorSubtractAssign)(void*, const void*);
void (*operatorMultiplyAssign)(void*, const void*);
void (*operatorDivideAssign)(void*, const void*);
};
// I won't repeat that long name all over the place...
typedef struct UselessCalculatorTemplateVirtualTable VirtualTable;
void UselessCalculatorConstruct(VirtualTable *table, void *this) {
table->constructInt(this, 0);
}
void UselessCalculatorCopy(VirtualTable *table, void *this, const void *what) {
table->copyConstruct(this, what);
}
void UselessCalculatorMove(VirtualTable *table, void *this, void *what) {
table->moveConstruct(this, what);
}
void UselessCalculatorDestruct(VirtualTable *table, void *this) {
table->destruct(this);
}
void UselessCalculatorAddAssign(VirtualTable *table, void *this, void *what) {
table->operatorAddAssign(this, what);
}
void UselessCalculatorAddAssign(VirtualTable *table, void *this, void *what) {
table->operatorSubtractAssign(this, what);
}
void UselessCalculatorMultiplyAssign(VirtualTable *table, void *this, void *what) {
table->operatorMultiplyAssign(this, what);
}
void UselessCalculatorDivideAssign(VirtualTable *table, void *this, void *what) {
table->operatorDivideAssign(this, what);
}
Now, the sole thing the compiler has to "instantiate" for each UselessCalculator<T> is the VirtualTable and helper functions (if any). For example, UselessCalculator<int> would translate to...
#define real(what) ((int*)what)
void constructInt(void *this, int what) {
*real(this) = what;
}
void copyConstruct(void *this, const void *what) {
*real(this) = *real(what);
}
void moveConstruct(void *this, void *what) {
*real(this) = *real(what);
}
void destruct(void *this) {}
void operatorAddAssign(void *this, const void *what) {
*real(this) += *real(what);
}
void operatorSubtractAssign(void *this, const void *what) {
*real(this) -= *real(what);
}
void operatorMultiplyAssign(void *this, const void *what) {
*real(this) *= *real(what);
}
void operatorDivideAssign(void *this, const void *what) {
*real(this) /= *real(what);
}
Then, taking this into account...
int main() {
UselessCalculator<int> myUselessCalc;
myUselessCalc += 10;
myUselessCalc *= 10;
myUselessCalc -= 10;
myUselessCalc /= 10;
}
VirtualTable virtualTableInt = {
&someFunkyImplementationOfStdTypeInfoForInt,
constructInt,
copyConstruct,
moveConstruct,
destroy,
addAssign,
subtractAssign,
multiplyAssign,
divideAssign
};
Could translate into this C code... (not taking exceptions into account!)
struct UselessCalculatorInt {
int result;
};
int main() {
int tmpStorage;
UselessCalculatorInt myUselessCalc;
UselessCalculatorConstruct(&virtualTableInt, &myUselessCalc);
tmpStorage = 10;
UselessCalculatorAddAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
tmpStorage = 10;
UselessCalculatorSubtractAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
tmpStorage = 10;
UselessCalculatorMultiplyAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
tmpStorage = 10;
UselessCalculatorDivideAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
UselessCalculatorDestroy(&virtualTableInt, &myUselessCalc);
return 0;
}
I know this would beat all the purpose of templates, a lot of people won't like the idea (I don't like it, I'm just curious), and the code will probably be less efficient, both CPU- and memory-wise, not to mention it's almost unoptimizable and they wouldn't be "templates" anymore. But other ones have abused them worse in the past, no? ;). BTW, better of to have a switch to disable this, if ever implemented, whenever necessary, because template metaprogramming would become near to useless.
So, my question is, if haven't been clear enough, is all this mess feasible, practical, implementable? Has some toolchain done this successfully? Would it provide any benefits that could outweight its obvious overheads?
Well, you are basically asking if some compiler can implement what is often called "compile-time polymorphism" (C++ templates) through run-time polymorphism ("classic" OOP with virtual functions).
While it is probably theoretically possible (at least to some limited degree), if really goes against the language design principles. Templates were provided specifically as an efficient replacement for run-time polymorphism in contexts where compile-time polymorphism is more appropriate. The whole purpose of templates is to be different from "ordinary" run-time polymorphism. And a lot of template features depend critically on their compile-time nature.
The idea is that if you used templates, it means that you want compile-time polymorphism, not run-time polymorphism.
That's one side of the medal. The other side is that poorly written template code can lead to unnecessary code bloat, by forcing compile-time polymorphism (i.e. repetitive instantiation of the same code) in situations where run-time polymorphism would have easily achieved the same thing with much less code bloat and with negligible performance penalty. From that point of view, implicit automatic switch to run-time polymorphism in template code might be beneficial. But I believe the language in its current state is not tailored for that. This is something that you are expected to explicitly do yourself.
I have a class design similar to the following:
class MyClass {
public:
bool IsValid() const;
void MakeValid();
private:
bool CheckValidity(bool fix);
};
bool MyClass::IsValid() const {
// Check validity, but don't fix any problems found. Doesn't work.
return CheckValidity(false);
}
void MyClass::MakeValid() {
// Check validity and fix problems found.
CheckValidity(true);
}
IsValid should be const, because it doesn't make changes. MakeValid should be non-const, because it does make changes. They share the same implementation, CheckValidity, but because CheckValidity may or may not make changes, it can't be marked const.
What's the best way to handle this? The simplest approach is to just use const_cast, but casting away const feels a bit dirty:
bool MyClass::IsValid() const {
// Check validity, but don't fix any problems found.
return const_cast<MyClass*>(this)->CheckValidity(false);
}
Is this a legitimate use of const_cast? Is there a better approach?
I'm assuming your implementation looks similar to this:
bool CheckValidity(bool fix)
{
// Actually check validity.
bool isValid = ...;
if (!isValid && fix)
{
// Attempt to fix validity (and update isValid).
isValid = ...;
}
return isValid;
}
You really have two different functions shoved into one. One of the key indicators of this kind of entanglement is the boolean argument to the function... which smells because the caller cannot immediately discern whether to put true or false without referencing code/docs.
Split up the method:
bool CheckValidity() const
{
// Actually check validity.
bool isValid = ...;
return isValid;
}
void FixValidity()
{
// Attempt to fix validity.
// ...
}
And then your public methods can make the calls more appropriately.
bool IsValid() const
{
// No problem: const method calling const method
return CheckValidity();
}
void MakeValid()
{
if (!CheckValidity()) // No problem: non-const calling const
{
FixValidity(); // No problem: non-const calling non-const
}
}
Here is an approach that might be useful in some cases. It might be overkill for your particular situation.
Your CheckValidity function could be passed a handler object. The CheckValidity function would find what was not valid, and call an appropriate method of the handler object. You could have many different methods for different kinds of validity violations, and those methods could be passed enough information that the problem could be fixed if necessary. To implement IsValid, you just need to pass a handler which sets a flag indicating there was a problem. To implement MakeValid, you can pass a handler which actually fixes the problem. The const issue is addressed by having the fixing handler keep a non-const reference to the object.
Here is an example:
class MyClass {
public:
bool IsValid() const
{
bool flag = false;
CheckValidity(FlagProblems{flag});
return flag;
}
void MakeValid()
{
CheckValidity(FixProblems{*this});
}
private:
struct FlagProblems {
bool& flag;
void handleType1(arg1,arg2) const { flag = true; }
void handleType2(arg1,arg2,arg3) const { flag = true; }
.
.
.
};
struct FixProblems {
MyClass& object;
void handleType1(arg1,arg2) const { ... }
void handleType2(arg1,arg2,arg3) const { ... }
.
.
.
};
template <typename Handler>
bool CheckValidity(const Handler &handler) const
{
// for each possible problem:
// if it is a type-1 problem:
// handler.handleType1(arg1,arg2);
// if it is a type-2 problem:
// handler.handleType2(arg1,arg2,arg3);
// .
// .
// .
}
};
Using the template allows for maximum efficiency. Alternatively, using a base class with virtual functions for the handler might provide a smaller executable size.
If the ways in which the object can be invalid are simpler, then having CheckValidity return a struct containing the relevant information may be more straightforward.
You can use a template specialization to separate the parts that only have purpose on a non-const object.
Following is an implementation for a toy class. It has a single c-array member v with 10 ints, and, for our purposes, it is only valid when every single one of them equals to zero.
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
};
See that I already made a function member that fixes an invalid position, and a nice constructor that initializes it as an invalid object(don't do that :D)
Since we are going to use templates, we need to move the implementation of the check/fix cycle outside of the class. In order for the relevant functions to be able to access v and the fix() method, we'll make them friends. Our code now looks like:
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
template<typename T>
friend void fix(T& obj, int pos);
template<typename T>
friend bool check(T& obj);
};
check()'s implementation is straightforward:
// Check and maybe fix object
template<typename T>
bool check(T& obj){
bool result = true;
for(int i=0;i<10;i++) {
if (obj.v[i]) {
result = false;
fix(obj, i);
}
}
return result;
}
Now here is the tricky part. We want our fix() function to change behaviour based on constness. For that we'll need to specialize the template. For a non-const object, it will fix the position. For a const one, it will do nothing:
// For a regular object, fix the position
template<typename T>
void fix(T& obj, int pos) { obj.fix(pos);}
// For a const object, do nothing
template<typename T>
void fix(const T& obj, int pos) {}
Finally, we write our is_valid() and make_valid() methods, and here we have the full implementation:
#include <iostream>
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
bool is_valid() const {return check(*this);} // since this is const, it will run check with a const ten_zeroes object
void make_valid() { check(*this);} // since this is non-const , it run check with a non-const ten_zeroes object
template<typename T>
friend void fix(T& obj, int pos);
template<typename T>
friend bool check(T& obj);
};
// For a regular object, fix the position
template<typename T>
void fix(T& obj, int pos) { obj.fix(pos);}
// For a const object, do nothing
template<typename T>
void fix(const T& obj, int pos) {}
// Check and maybe fix object
template<typename T>
bool check(T& obj){
bool result = true;
for(int i=0;i<10;i++) {
if (obj.v[i]) {
result = false;
fix(obj, i);
}
}
return result;
}
int main(){
ten_zeroes a;
std::cout << a.is_valid() << a.is_valid(); // twice to make sure the first one didn't make any changes
a.make_valid(); // fix the object
std::cout << a.is_valid() << std::endl; // check again
}
I hope you don't mind the main() function there. It will test our little toy, and output 001, as expected. Now any maintenance on this code will not have to deal with code duplication, what you probably was intending to avoid. I hope this was helpful.
Of course, if you intend to hide these implementation details from the final user, you should move them to an appropriate detail namespace. I'll leave that up to you :)
after yesterday's rip-roaring thread at How to implement a simple event queue? , I decided to finally make the big leap to c++11. Just before c++14 comes out probably...
Anyway, it occured to me that variadic functions are the perfect way forward in this enjoyable endeavour. They probably aren't really, but anyway, I managed to steal and bastardize some code I found somewhere, and ended up with this:
#include <iostream>
#include <functional>
#include <queue>
class Event
{
public:
int timeOfCompletion;
std::function<void()> function;
inline bool operator<(const Event& target) const
{
return target.timeOfCompletion < timeOfCompletion;
}
};
class System
{
public:
int someValue;
std::priority_queue<Event> funcs;
System()
{
someValue = 100;
}
template<typename Func, typename...Args>
void addFunctionToQueue(const int t , const Func&& myFunc, Args&&... myArgs)
{
Event newEvent;
std::function<void()> func = std::bind( std::forward<Func>(myFunc), std::ref(myArgs)...);
newEvent.function = func;
newEvent.timeOfCompletion = t;
funcs.push(newEvent);
}
void runAllFunctions()
{
while(!funcs.empty())
{
Event func = funcs.top();
funcs.pop();
func.function();
}
}
static void doStaticFunction(int a)
{
std::cout <<"I would like to change someValue here, but can't :-(\n";
//someValue -= a;//invalid
}
void doNonStaticFunction(int a)
{
someValue -= a;
std::cout <<"Set someValue to " << someValue << "\n";
}
};
int main()
{
System newSystem;
newSystem.doNonStaticFunction(5);
newSystem.addFunctionToQueue(5, System::doStaticFunction, 1);
newSystem.runAllFunctions();
//newSystem.addFunctionToQueue(5, newSystem.doStaticFunction, 1);// is invalid
//newSystem.addFunctionToQueue(5, System::doNonStaticFunction, 1);// is invalid
//newSystem.addFunctionToQueue(5, newSystem.doNonStaticFunction, 1);// is invalid
std::cin.ignore();
return 0;
}
Anyhow, how can I get the "addFunctionToQueue" function to work with non-static functions? I thought I had more questions, but I think if I can get that one answered, my other problems will hopefully be solved...
Remove a const qualifier from the Func parameter.
template<typename Func, typename...Args>
void addFunctionToQueue(int t , Func&& myFunc, Args&&... myArgs)
// ~~~^ no const
Rationale: When using a forwarding reference (or an lvalue reference) type with a template argument deduction, a const qualifier is automatically deduced (depending on the argument's qualifiers). Giving it explicitly prevents the compiler from adding it to the Func type itself, which results in an error when you try to std::forward<Func>. That said, you would need to write std::forward<const Func> instead to avoid the compiler error, but still, that would make no sense, as const T&& is not a forwarding reference.
Non-static member functions require an object for which they will be called, just like you write a.foo(), not foo().
newSystem.addFunctionToQueue(5, &System::doNonStaticFunction, &newSystem, 1);
// ~~~~~~~~~^ context
Even though I fear that you will tell me that this topic was covered several time, I dare to ask it, since I was not able to generate a solution. Probably I was just looking for the wrong thing...
Assume that I have a function which receives a "mode" from some external function. Depending on the mode, the function will call different member functions of the same object. This works well for me with member function without any argument, but I did not find out how to extend it to members with arguments. In the real world application, the arguments are not int/float but a more complex classes and the call is nested inside different loops, so I would need to put switch statements several times which I consider ugly.
Question A: Is it possible to easily add support for member functions with arguments based on the existing design? If yes, how does one do that? If possible without external libraries...
Question B: Is this a completely wrong/bad approach? How would I do it better?
Thanks a lot for your help and explanations.
Chris
header excerpt:
typedef void (Object::*memberFunction)();
class Object
{
void memberFnNoArg();
void memberFnWithIntArg(int arg);
void memberFnWithFloatArg(float arg);
}
cpp excerpt:
void function()
{
int mode = getModeFromSomewhere();
int intArg = 33;
float floatArg = 66.6;
switch(mode)
{
case 1:
process(&Object::memberFnNoArg);
break;
case 2:
process(&Object::memberFnWithIntArg, ???); // how can I pass arg?
break;
case 3:
process(&Object::memberFnWithFlaotArg, ???); // how can I pass arg?
break;
default:
// do nothing;
}
}
void process(Object::memberFunction func)
{
Object object;
// loops, called several times, ...
(object.*func)(); // how do I handle different arguments?
}
Wrapping the algorithm in a functor is the right approach, and std::function is a nice functor provided by the Standard library.
But using boost::bind or even std::bind, as suggested by Tomek, is really ugly IMO, and rapidly gets out of control when binding multiple arguments.
If you have a recent compiler you can use a lambda instead, which makes Tomek's example look like:
std::function<void(Object*)> f =
[](Object* const that){ that->memberFnNoArg(); };
int int_value = 22;
std::function<void(Object*)> f2 =
[int_value](Object* const that){ that->memberFnIntArg(int_value); };
Object o;
f(&o);
f2(&o);
There are a few characters to set up the lambda, but the member access syntax is extremely natural and it's obvious how you make changes.
Of course, you can make the parameter a reference to the object if you really want, but I prefer pointers here.
Have a look at std::function and std::bind, they seem to fit perfectly what you need.
EDIT:
std::function<void(Object &)> f = &Object::memberFnNoArg;
std::function<void(Object &)> f2 = std::bind(&Object::memberFnWithIntArg, _1, 22);
Object o;
f(o);
f2(o);
should work out of a box as far as I remember.
Is this what you need?
You could use a varadic template function:
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
Here is a full example:
#include <iostream>
struct Object
{
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
};
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
int main()
{
process(&Object::memberFnNoArg);
process(&Object::memberFnWithIntArg,5);
process(&Object::memberFnWithFloatArg,2.7F);
return 0;
}
One way I see around this would be to use a variable arguments (pretty much like printf, sprintf does it). (Or maybe with stdc libraries, passing a list of different types.)
The reason is, that the argument list is part of the function pointer type, so you'd essentially need a process function with variable arguments and then the memberFunction probably needs to be one of that type too.
Below is a plain (non member) sample of how to pick up variable arguments (member functions would essentially work the same). See stdarg.h.
typedef void (*var_function)(int typearg, ...);
void print_arg(int typearg, ...)
{
va_list ap;
int i;
va_start(ap, typearg);
if (typearg==1) { // int
int i= va_arg(ap, int);
printf("%d ", i);
}
else
if (typearg==2) { // float
float f= va_arg(ap, float);
printf("%f ", f);
}
else
if (typearg==3) { // char *
char *s= va_arg(ap, char *);
printf("%s ", s);
}
....
va_end(ap);
}
// calling function with different types
int main()
{
print_arg(1, 999);
print_arg(2, 3.1415926);
print_arg(3, "Hello");
....
process(print_arg, 3, "via pointer);
Sounds like packaged_task. Also check out Tomek's suggestion.
Though IRL I'd go ahead asking lots of questions on why you need it in the first place. Possibly your work could be better covered using std::future or other higher level facility,
Can't each function (memberFn**) be a member of argument classes ?
class BaseArg
{
virtual void Fn() = 0;
};
class IntArg : public BaseArg
{
void Fn();
};
class FloatArg : public BaseArg
{
void Fn();
};
void function()
{
int mode = getModeFromSomewhere();
BaseArg* pArg;
if ( mode ... ){
pArg = new IntArg( 33 );
}
else {
pArg = new FloatArg( 66.6 );
}
pArg->Fn(); // Call the right function without a switch
// and without knowing the arguments
}
Same as other answers, but to show for member methods:
#include <iostream>
class Object
{
public:
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
bool memberFnWithBoolReturn(int)
{
return true;
}
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args);
// overload process
template <typename... Args>
bool process(bool (Object::*func)(Args...),Args... args);
};
template <typename... Args>
void process( void (Object::*func)(Args...),class Object* obj,Args... args)
{
(obj->*func)(args...);
}
template <typename... Args>
bool process( bool (Object::*func)(Args...),class Object* obj,Args... args)
{
return ((obj->*func)(args...)) ;
}
int main()
{
Object object;
process(&Object::memberFnNoArg,&object);
process(&Object::memberFnWithIntArg,&object,5);
process(&Object::memberFnWithFloatArg,&object,2.7F);
// overloaded process
printf("%d\n",process(&Object::memberFnWithBoolReturn,&object,1));
return 0;
}
i was wondering if there was a way to do this in C++?
void func1(const std::string& s)
{
std::cout << s << std::endl;
}
void func2(int me)
{
std::cout << me << std::endl;
}
int main()
{
std::map<std::string, boost::function< ??? > > a_map;
a_map["func1"] = &func1;
a_map["func1"]("HELLO");
}
Is there any way to do what i have above using boost function and a map?
There are ways to store the functions, the problem is, in order to be able to call the function with the desired argument you'd have to know the calling signature of the function anyways, and if you have that information, you might as well use separate maps, or use a more complicated object than boost::function.
If you're willing to do a bit of work and have a finite number of signatures, you could just do something like this:
class MultiFunc
{
protected:
MultiFunc() {}
public:
typedef void (*stringFunc)(const std::string&);
typedef void (*intFunc)(int);
static MultiFunc *Create(stringFunc function);
static MultiFunc *Create(intFunc function);
virtual void operator()(const string &) { throw exception(); }
virtual void operator()(int) { throw exception(); }
virtual ~MultiFunc();
};
class MultiFuncString : public MultiFunc
{
private:
stringFunc Function;
public:
MultiFuncString(stringFunc function) : Function(function) {}
virtual void operator()(const string &arg) { Function(arg); }
};
class MultiFuncInt : public MultiFunc
{
private:
intFunc Function;
public:
MultiFuncInt(intFunc function) : Function(function) {}
virtual void operator()(int arg) { Function(arg); }
};
MultiFunc *MultiFunc::Create(MultiFunc::stringFunc function)
{
return new MultiFuncString(function);
}
MultiFunc *MultiFunc::Create(MultiFunc::intFunc function)
{
return new MultiFuncInt(function);
}
void func1(const std::string& s)
{
std::cout << s << std::endl;
}
void func2(int me)
{
std::cout << me << std::endl;
}
int main()
{
map<string, MultiFunc *> a_map;
a_map["func1"] = MultiFunc::Create(&func1);
(*a_map["func1"])("Hello");
a_map["func2"] = MultiFunc::Create(&func2);
(*a_map["func2"])(3);
// Remember to delete the MultiFunc object, or use smart pointers.
}
This outputs:
Hello
3
Unfortunately, you can't make templated virtual functions or you easily generalize this all.
You probably can't use the std::map since it is a homogenous container. Try, something like boost::variant (they support the visitor pattern) or boost::tuple
What you are trying to do sounds a little weird. Normally, you would have a container be a collection of abstract types or objects or functions with the same signature. Otherwise, how would you know how to call the function when you are iterating the container? I like to make the container a collection of function objects with a known signature, then use Boost.Bind to store closures that call the function with additional arguments.
For example:
typedef boost::function<void, void> Function;
typedef std::map<std::string, Function> Functions;
Functions functions:
void foo()
{
...
}
functions["foo"] = foo;
void bar(std::string &s)
{
...
}
// binds the value "hello" to the s parameter
functions["bar"] = boost::bind(bar, "hello");
read this link below. It talks about using boost::bind to store the function pointers in std::map
http://www.gamedev.net/community/forums/topic.asp?topic_id=526381&whichpage=1�
store interfaces:
struct IStringData
{
virtual std::string get() const = 0;
virtual ~IStringData() {}
};
and make implementaions, one will just hold string value, other implementation will store functor, maybe you will have other implementations in future.
No. You can't. Since boost::function isn't polymorphic, it breaks down there. (It takes a fixed set of argument types.)
There was talk about work in that direction on the boost mail-list, though, so search the archives and see if there is some code you could youse.
A workaround would be to use boost::function but then you need to add to the map not your real functions (i.e. func1/func2) but dispatch functions that extracts the type from the any-container and calls the real function. (And bails if it's wrong, just as in any dynamic langugage.)