I have to use a function in library with variable parameters (createObject), the general usage is:
Class Point
{
public:
Point() {};
int x;
int y;
const char* name;
}
int main()
{
Point p;
createObject("%d",p.x,"%f",p.y,"%d",1,"%s",p.name);
}
Now i want to generalize usage of this function with Macro and Template, like this:
#define PARAM_Matrix(obj) "%d",obj.m,"%d",obj.n,"%d %d",obj[0][0],"%d %d",obj[0][1],"%d %d",obj[0][2]
#define PARAM_Person(obj) "%d",obj.age,"%s",obj.name
#define PARAM_Point(obj) "%d",obj.x,"%f",obj.y,"%d",1,"%s",obj.name
#define MAKE_PARAM(className,obj) PARAM_##className(obj)
class Person;
class Matrix;
class Point
{
public:
Point() {};
int x;
int y;
const char* name;
}
template<typename T> createGeneralize(T t)
{
return createObject(MAKE_PARAM(T,t));
}
int main()
{
Person per;
Matrix m;
Point p;
createGeneralize<Person>(per);
createGeneralize<Matrix>(m);
createGeneralize<Point>(p);
}
I expected that in createGeneralize() the C++ compiler expanding the macro to MAKE_PARAM(Point,t) (or MAKE_PARAM(Matrix,t)...). However, it is not the case, it always expands to MAKE_PARAM(T).
Your idea is not feasible because the preprocessor macros are converted to text before actual compiling. while the template arguments are substituted during compilation. so you get something like:
doMore (Point p)
{
T u, v; u = v;
}
i suggest just use templates.
Instead of macro, you may use template:
auto as_tuple(const Person& obj) { return std::make_tuple("%d", obj.age, "%s", obj.name); }
auto as_tuple(const Matrix& obj) { return std::make_tuple("%d", obj.m,"%d",obj.n,"%d %d",obj.obj[0][0],"%d %d",obj.obj[0][1],"%d %d",obj.obj[0][2]); }
auto as_tuple(const Point& obj) { return std::make_tuple("%d", obj.x,"%f",obj.y,"%d",1,"%s",obj.name); }
template<typename Tuple, std::size_t...Is>
void createGeneralize(const Tuple& t, std::index_sequence<Is...>)
{
return createObject(std::get<Is>(t)...);
}
template<typename T> void createGeneralize(const T& t)
{
const auto& tuple = as_tuple(t);
return createGeneralize(tuple, std::make_index_sequence<std::tuple_size<std::decay_t<decltype(tuple)>>::value>());
}
Live example
Related
I would like to have some fair idea how to map functions with variable arguments,return type of int and call it by a string..
Just for an example...
int func1(int a, int b);
int func2(int a1, int b1 , int* c1);
int func3(char* dummy);
int func4(double x, long y, int z, char** table);
int func5(double d1, double b1);
int func6(int* p, double* q, int i);
I just need a common function called
int CallFunction("funcname", param1, param2, ...);
for example
CallFunction("func1", 10, 20); /* calling function func1 and return func1 result*/
I know how to map functions using functions pointers having constant arguments but variable arguments seems to be complicated.. could anyone shower some idea how to do it.
I even explored Variadic templates.. But seems to complicated calling functions using strings..
I had exact the same problem.
Solved it with this solution:
#include <iostream>
#include <map>
#include <string>
int func0(int x)
{
std::cout << x << std::endl;
}
int func1(int x, int y)
{
std::cout << (x + y) << std::endl;
}
template <class... Args>
struct MapHolder{
static std::map<std::string, int (*)(Args...)> CallbackMap;
};
template <class... Args>
std::map<std::string, int (*)(Args...)> MapHolder<Args...>::CallbackMap;
class Callback {
public:
template <class ...Args>
void RegisterFunction(std::string name, int (*func)(Args...)) {
MapHolder<Args...>::CallbackMap[name] = func;
}
template <class ...Args>
int ExecuteFunction(std::string name, Args &&... args) {
return MapHolder<Args...>::CallbackMap[name](std::forward<Args>(args)...);
};
};
int main(int argc, char *argv[])
{
Callback cb;
cb.RegisterFunction("func0", &func0);
cb.RegisterFunction("func1", &func1);
cb.ExecuteFunction("func0", 42);
cb.ExecuteFunction("func1", 42, 42);
return 0;
}
This snippet is based on this answer. I only use other class/function names.
I'm not sure if this is what you're looking for, but anyway...
1. Creating a generic value holder
boost.any didn't make it into the standard, and, in case you don't know what it is, it allows you to store any C++ value in a single type (any) and get it back if you know the type. The following is a toy implementation of it:
struct TypeHandler {
void* (*copyFrom)(void *src);
void (*destroy)(void *p);
};
template<typename T>
TypeHandler *thandler() {
struct THandler {
static void *copyFrom(void *p) { return new T(*(T *)p); }
static void destroy(void *p) { delete (T *)p; }
};
static TypeHandler th = { &THandler::copyFrom, &THandler::destroy };
return &th;
}
TypeHandler contains two pointer to functions that know how to copy and how to destroy a specific C++ type. A Value can hold any type because it's composed of a void * and a pointer to a TypeHandler. When copying or destroying is required on the instance it asks to the specific type handler function...
struct Value {
TypeHandler *th;
void *p;
Value(const Value& other) : th(other.th), p(th->copyFrom(other.p)) { }
template<typename T> Value(const T& x) : th(thandler<T>()), p(new T(x)) { }
~Value() { th->destroy(p); }
Value& operator=(const Value& other) {
if (this != &other) {
th->destroy(p);
th = other.th;
p = th->copyFrom(other.p);
}
return *this;
}
template<typename T>
Value& operator=(const T& other) {
th->destroy(p);
th = thandler<T>();
p = new T(other);
return *this;
}
template<typename T>
T& to() const {
if (th != thandler<T>()) throw Error("type mismatch");
return *(T*)p;
}
};
Note that Value is copyable and can be passed by value and can be returned by functions.
Any copyable object is implicitly convertible into a Value and I can also convert it back to the original type with to<T>().
2. Creating the name->function maps
std::map<std::string, Value (*)(const Value&)> map1;
std::map<std::string, Value (*)(const Value&, const Value&)> map2;
Value call(const std::string& name, const Value& x1) {
return map1.at(name)(x1);
}
Value call(const std::string& name, const Value& x1, const Value& x2) {
return map2.at(name)(x1, x2);
}
Here I've created explicit maps for 1 and 2 arguments. May be this can be done using C++11 variadic templates, I didn't try. In C++03 libraries it's common to see this kind of stuff copy-n-pasted up to say n=20 to cover reasonable cases.
3. Macrology
To simplify registration of functions I wrote two ugly macros. May be this can be done also using variadic macros or templates (I'm not so sure about it, especially the automatic registration of the wrapper in the map).
#define regfunc1(name, t1) \
Value name(const Value& x1) { \
return name(x1.to<t1>()); \
} \
struct name##_ { \
name##_() { map1[#name]=&name; } \
} name##_instance
#define regfunc2(name, t1, t2) \
Value name(const Value& x1, const Value& x2) { \
return name(x1.to<t1>(), x2.to<t2>()); \
} \
struct name##_ { \
name##_() { map2[#name]=&name; } \
} name##_instance
4. Use
double square(double x) {
return x*x;
}
double hyp2(double x, double y) {
return x*x+y*y;
}
int mylen(const std::string& s) {
return s.size();
}
regfunc1(square, double);
regfunc2(hyp2, double, double);
regfunc1(mylen, std::string);
int main() {
Value x = 42;
Value y = std::string("This is a test");
Value z = 3.14;
printf("%0.3f\n", call("square", z).to<double>());
printf("%0.3f\n", call("hyp2", z, z).to<double>());
printf("mylen(\"%s\") = %i\n",
y.to<std::string>().c_str(),
call("mylen", y).to<int>());
return 0;
}
I am trying to pass a function pointer in to a constructor of a class. However, when I try to compile the code, I am getting an error. The code and error are :
quickfind.h
#ifndef QUICKFIND_H
#define QUICKFIND_H
#endif // QUICKFIND_H
template <class T>
class QuickFind
{
private:
int size;
int *array;
int (*giveIndex)(const void *a);
public:
QuickFind<T>(int n,int (*ptr)(const void *));
void connect (const T* u,const T* v);
bool isConnected(const T* u,const T* v);
};
Constructor definition in file quickfind.cpp
template <class T>
QuickFind<T>::QuickFind(int n,int (*ptr)(const void *))
{
size=n;
array=new int[n];
giveIndex=ptr;
for(int i=0;i<n;i++)
{
array[i]=i;
}
}
In my main function file :
int giveIndex (const void *ptr)
{
temp *tptr=(temp*)ptr;
return tptr->getA();
}
int main()
{
QuickFind<temp> *qf=new QuickFind<temp>(10,giveIndex);
}
Here, I am getting 'undefined reference to QuickFind<temp>::QuickFind(int, int (*)(void const*))' error. I am not able to figure out the problem...please help.
One thing wrong, you don't need the on the constructor:
template <class T>
class QuickFind
{
private:
int size;
int *array;
int (*giveIndex)(const void *a);
public:
QuickFind(int n,int (*ptr)(const void *)); /// <---- here, no <T>
void connect (const T* u,const T* v);
bool isConnected(const T* u,const T* v);
};
In your case, the class it templated, but this function isn't. And, template functions must be defined in the header file so that the file that includes them can see the code and substitute the parameter types.
Put all of the following in one CPP file to see it work. As noted in other comments you must, for templated classes, put the entire definition in the header file. Do not separate the function declaration from its definitions into a separate CPP file. In this case having the entire implementation in the one CPP file serves the same purpose.
I have made some changes to your code to make it typesafe, memory leak safe and more exception safe. For example I replaced your dynamically allocated array with std::vector. std::vector has all the features you need but manages the memory for you and will be cleaned up when your class goes out of scope.
#include <vector>
#include <iostream>
#include <functional>
template <typename T>
class QuickFind
{
private:
std::vector<int> data;
std::function<int (const T&)> func;
public:
QuickFind(int n, std::function<int (const T&)> f) : data(n), func(f)
{
int i = 0;
for(auto it = data.begin(); it != data.end(); ++it)
data[i]=i++;
}
void connect (const T& u, const T& v)
{
std::cout << func(u) << "\n";
std::cout << func(v) << "\n";
}
bool isConnected(const T* u,const T* v);
};
class temp
{
int val;
public:
temp(int i) : val(i)
{}
int getA() const
{
return val;
}
};
int giveIndex (const temp &t)
{
return t.getA();
}
int main()
{
temp t1(5), t2(10);
QuickFind<temp> qf1(10,giveIndex);
qf1.connect(t1, t2);
// this example uses a lambda as the callback
auto giveIndex2 = [](const temp& t) { return t.getA(); };
QuickFind<temp> qf2(20, giveIndex2);
qf2.connect(t1, t2);
}
The compiler wants to know objects of which types will be instantiated from a template class at the time of compilation of template class methods. So, there may arise compile-time or link-time errors.
This explains more about various errors and their causes.
Adding #include "quickfind.cpp" in the end of the header file worked in my case after some efforts.
I need to do something like this:
template <typename Matrix_xx>
bool ProcessMatrix<Matrix_xx>::function1(Matrix_xx a) {
int x, y;
// ... some code here ... //
if (Matrix_xx == Matrix_1D) {
a->readFromFile(x);
} else if (Matrix_xx == Matrix_2D) {
a->readFromFile(x, y);
} // ...
}
i.e., to call different functions depends on the template argument. The code above wouldn't compile because there are only Matrix_1D::readFromFile(int x) and Matrix_2D::readFromFile(int x, int y). I don't want to split function1 into two different functions only because there would be a lot of doubled code. Is there another way?
Wrap the type-specific code in either overloaded function or explicitly specialized template:
void doReadFromFile(Matrix_1D &a, int x, int y)
{
a->readFromFile(x);
}
void doReadFromFile(Matrix_2D &a, int x, int y)
{
a->readFromFile(x, y);
}
template <typename Matrix_xx>
bool ProcessMatrix<Matrix_xx>::function1(Matrix_xx a) {
int x, y;
// ... some code here ... //
doReadFromFile(a, x, y);
}
If Matrix_xx is Matrix_1D, overloading will select the first overload, if it is Matrix_2D, overloading will select the second overload and if it's anything else, it won't compile. But if somebody provides new type of matrix, they can make it compile by defining the doReadFromFile for it.
This is generally useful trick and reason why standard library uses "traits"—they can be defined for class somebody gives you and they can be defined for non-class types. The "traits" can be either in the form of explicitly specialized templates or free functions, usually looked up with argument-dependent lookup (placed in the namespace of their argument, not the template).
For completeness, the explicit specialization would look like:
template <typename Matrix_xx>
struct doReadFromFile {};
template <>
struct<Matrix_1D> struct doReadFromFile {
void operator()(Matrix_1D &a, int x, int y) {
a->readFromFile(x);
}
}
template <>
struct<Matrix_1D> struct doReadFromFile {
void operator()(Matrix_1D &a, int x, int y) {
a->readFromFile(x, y);
}
}
Couldn't you make the argument to readFromFile a reference to a vector and let the Matrix_xx instance decide how many indices to fill in? That would eliminate the need for a conditional check.
You can get around that using the typeid operator.
Using it, your code would become:
template <typename Matrix_xx>
bool ProcessMatrix<Matrix_xx>::function1(Matrix_xx a) {
int x, y;
// ... some code here ... //
if (typeid(Matrix_xx) == typeid(Matrix_1D)) {
a->readFromFile(x);
} else if (typeid(Matrix_xx) == typeid(Matrix_2D)) {
a->readFromFile(x, y);
} // ...
}
or you could do it with a switch:
switch(typeid(Matrix_xx))
{
case typeid(Matrix_1D):
a->readFromFile(x);
break;
case typeid(Matrix_2D):
a->readFromFile(x,y);
break;
// etc, etc
}
[EDIT:] For those that say it won't compile, I'd be most interested in knowing what the functional difference between the code I left above and the code below, which is taken from a working project:
pdfArray.h
#ifndef PDFARRAY_H
#define PDFARRAY_H
#include "pdfObj.h"
#include "pdfTypes.h"
class pdfArray : public pdfObj
{
public:
pdfArray();
pdfArray(const pdfArray &src);
size_t size()
{
return(mArray->size());
}
void clear();
~pdfArray();
template <typename T> void addItem(const T *newItem)
{
//cout << typeid(T).name() << endl;
pdfObj *item = new T(*newItem);
mArray->push_back(item);
}
pdfObj *getItem(unsigned int itemIndex);
const bstring& toString();
pdfArray &operator=(const pdfArray &src);
private:
vecObjPtr *mArray;
};
#endif // PDFARRAY_H
excerpt from pdfArray.cpp
pdfArray::pdfArray(const pdfArray &src)
{
vecObjPtrIter iter;
pdfObj *ptr;
mArray = new vecObjPtr;
for (iter=src.mArray->begin(); iter!=src.mArray->end(); iter++)
{
ptr = *iter;
if (typeid(*ptr) == typeid(pdfString))
addItem( (pdfString*)ptr );
if (typeid(*ptr) == typeid(pdfInt))
addItem( (pdfInt*)ptr );
if (typeid(*ptr) == typeid(pdfFloat))
addItem( (pdfFloat*)ptr );
if (typeid(*ptr) == typeid(pdfArray))
addItem( (pdfArray*)ptr );
}
}
As an exercise for my personal enlightenment, I implement vector math with expression templates. I want to implement some operations that apply the same unary function to all elements to a vector expression. So far, I do this.
My base vector expression template is implemented like this
template <typename E>
class VectorExpr {
public:
int size() const { return static_cast<E const&>(*this).size(); }
float operator[](int i) const { return static_cast<E const&>(*this)[i]; }
operator E& () { return static_cast<E&>(*this); }
operator E const& () const { return static_cast<const E&>(*this); }
}; // class VectorExpr
Then, an object supposed to be a vector will look like this
class Vector2 : public VectorExpr<Vector2> {
public:
inline size_t size() const { return 2; }
template <typename E>
inline Vector2(VectorExpr<E> const& inExpr) {
E const& u = inExpr;
for(int i = 0; i < size(); ++i)
mTuple[i] = u[i];
}
private:
float mTuple[2];
};
Let's say I want to apply std::sin to all elements of an expression
template <typename E>
class VectorSin : public VectorExpr<VectorSin<E> > {
E const& mV;
public:
VectorSin(VectorExpr<E> const& inV) : mV(inV) {}
int size() const { return mV.size(); }
float operator [] (int i) const { return std::sin(mV[i]); }
};
Question => If I want to add more functions, I copy-paste what I do for the sin function, for every single function (like cos, sqrt, fabs, and so on). How I can avoid this kind of copy-pasting ? I tried things and figured out I'm still low in template-fu. No boost allowed ^^
template <typename F, typename E>
class VectorFunc : public VectorExpr<VectorFunc<F, E> > {
E const& mV;
public:
VectorSin(VectorExpr<E> const& inV) : mV(inV) {}
int size() const { return mV.size(); }
float operator [] (int i) const { return f(mV[i]); }
// this assumes the Functor f is default constructible, this is
// already not true for &std::sin. Adding the constructor that
// takes f, is left as an exercise ;)
F f;
};
In addition to the answer by pmr, The standard <cmath> functions aren't functors, so you couldn't use them directly to specify unique specialisations of your class - i.e. you wouldn't have a separate template instantiation for std::sin versus std::cos (which is what I gather you're aiming for? correct me if I've misunderstood you on that).
You could create a wrapper in order to map a function pointer to a distinct type, e.g.
#include <iostream>
template< void (*FuncPtr)() > struct Func2Type
{
void operator() () { FuncPtr(); }
};
void Hello() { std::cout << "Hello" << std::endl; }
void World() { std::cout << "world" << std::endl; }
int main()
{
Func2Type<Hello> test1;
Func2Type<World> test2;
test1();
test2();
}
That way you could use them as template arguments in the same way as a normal functor class
I have two methods f(vector<int>& x, ....) and g(DBConn& x, ....)
where the (....) parameters are all identical.
The code inside the two methods are completely identical except for one statement
where we do different actions based on the type of x:
in f(): we do x.push_back(i)
in g(): we do x.DeleteRow(i)
What is the simplest way to extract the common code into one method and yet
have the two different statements?
I am thinking of having a templated functor that overloads operator () (int a) but that seems overkill.
common_function(....)
{
}
f(vector<int>x,... )
{
x.push_back(i);
common_f(...);
}
g(DBConn& x, ....)
{
x.DeleteRow(i);
common_f(...);
}
You could write a simple adapter with two implementations, each calling the desired method of a different class.
class MyInterface {
public:
virtual doIt(int i) = 0;
}
class VectorImp : public MyInterface {
public:
vector<int>& v;
VectorImp(vector<int>& theVector) : v(theVector) {}
doIt(int i) { x.push_back(i); }
}
class DbImp : public MyInterface {
public:
DBConn& c;
VectorImp(DBConn& conn) : c(conn) {}
doIt(int i) { c.DeleteRow(i); }
}
template<class T>
struct Adapter;
template<>
struct Adapter<vector<int> >
{
static void execute(vector<int> &x, int i)
{
x.push_back(i);
}
};
template<>
struct Adapter<DBConn>
{
static void execute(DBConn &x, int i)
{
v.DeleteRow(i);
}
};
template<class T>
void f(T &t, ...)
{
...
Adapter<T>::execute(t, i);
...
}
OR:
template<class T>
struct adapter_traits;
template<>
struct adapter_traits<vector<int> >
{
typedef void (vector<int>::*PMF)(int);
static const PMF pmf = &vector<int>::push_back;
}
template<>
struct adapter_traits<DBConn>
{
typedef void (DBConn::*PMF)(int);
static const PMF pmf = &DBConn::DeleteRow;
}
template<class T>
void f(T &t, ...)
{
...
(t.*adapter_traits<T>::pmf)(i);
...
}
NOTE: I might have some syntax wrong but you get the idea.
Yet another idea:
template<class T>
void f(T &t, void (T::*p)(int), ...)
{
...
(t.*p)(i);
}
void g()
{
DBConn x;
vector<int> y;
f(x, &DBConn::DeleteRow, ...);
f(y, &vector<int>::push_back, ...);
}
Classic case for a functor:
#include <vector>
#include <DBConn.h>
// T: The type of the object that is to be manipulated.
// A: The type of the object that will do the manipulating
// This may be a functor object or a function pointer.
//
// As this is a template function the template parameters will
// be deduced by the compiler at compile time.
template<typename T,typename A>
void action(T& obj,A const& action/*,....*/)
{
// Do Stuff
action(obj,5);
// Do more Stuff
}
// Functor object
struct MyVectorAction
{
// Just defines the operator()
// Make sure it is a const method.
// This does the unique bit of code. The parameters should be what you pass into action
void operator()(std::vector<int>& data,int val) const {data.push_back(val);}
};
void f(std::vector<int>& x)
{
action(x,MyVectorAction()/*.... Params ....*/);
}
struct MyDBConnAction
{ void operator()(DBConn& data,int val) const {data.DeleteRow(val);} };
void g(DBConn& x)
{
action(x, MyDBConnAction());
}
int main()
{
std::vector<int> x;
f(x);
}
You could make a function that has the parameters of what you call (...), and this function can implement the logic that is the same in f() and g(). You could then change the implementation of f() and g() to call this new function instead of duplicating the logic. Be careful though if you're doing something duplicated before and after your unique lines. You may need two functions in that case. At any rate I think this would be preferable to having duplicated blocks of code.