I want to store a pointer to member function in some kind of object. Later in the programm i want to compare it to another one.
Requirenment is that the type of object that holds first pointer must be concrete (i need to store them in one container)
I failed to apply Type-erasure here because template functions can not be virtual, so i can not provide an interface "compareWith" to be overridden.
There is a half-working solution i came up with, but the problem here is with the types of Fnc objects - those are different and can not be stored in the same container. I do need to store them in the same container.
Simplified version is below:
template<class T>
class Fnc
{
public:
Fnc(T&& fnc) : m_fnc(std::forward<T>(fnc)) {}
template<class Y>
bool compareWith(const Fnc<Y>& other) {
return other.m_fnc == m_fnc;
}
private:
T m_fnc;
};
class MyClass
{
public:
void method1(int a);
void method2(int a);
void method3();
}
int main() {
//This block obviously works because i didnt try to put Fnc-objects to container
Fnc fnc1(&MyClass::method1);
Fnc fnc2(&MyClass::method2);
printf("%d\n", fnc1.compareWith(Fnc(&MyClass::method1))); //prints "1"
printf("%d\n", fnc1.compareWith(Fnc(&MyClass::method3))); //prints "0"
printf("%d\n", fnc2.compareWith(Fnc(&MyClass::method2))); //prints "1"
//This block is not working because Fnc is not polymorphic(and cannot be - template functions can not be virtual)
std::vecotor<Fnc> methods;
methods.push_back(Fnc(&MyClass::method1));
methods.push_back(Fnc(&MyClass::method2));
methods.push_back(Fnc(&MyClass::method3));
printf("%d\n", methods[0].compareWith(Fnc(&MyClass::method1))); //should be "1"
printf("%d\n", methods[1].compareWith(Fnc(&MyClass::method2))); //should be "1"
printf("%d\n", methods[2].compareWith(Fnc(&MyClass::method3))); //should be "1"
printf("%d\n", methods[0].compareWith(Fnc(&MyClass::method2))); //should be "0"
}
With a hint given by #joergbrech i made up some kind of hash that easily distinguishes one pointer to member function from another. And it works with overloads too.
The solution is very simple, yet may not be very robust. But it works nicely for me. The benefit is that it works with C++11 and doesnt require any fancy stuff :)
Working example:
//WARINING: sizeof(pointer-to-member-function) may not always be <= 8
//Consider changing the hash to be an array!
//I write it as uint64_t for the sake of ease.
template<typename R, class Class, class... Args>
uint64_t getId(R(Class::*ptr)(Args...)) {
uint64_t id = 0;
memcpy(&id, &ptr, sizeof(ptr));
return id;
}
class MyClass
{
public:
void test(int a) {
}
void test(double a) {
}
void test2(int a) {
}
};
int main() {
//Now every pointer-to-member-function may be simply represented by a number
//and compared at any time.
//static_cast is needed for functions that are overloaded if you wonder.
cout << getId(static_cast<void(MyClass::*)(int)>(&MyClass::test))
<< getId(static_cast<void(MyClass::*)(double)>(&MyClass::test))
<< getId(static_cast<void(MyClass::*)(double)>(&MyClass::test))
<< getId(&MyClass::test2);
//Output was: 4389464 4389304 4389304 4389616
// ^ != ^ == ^ != ^
return 0;
}
Related
I have a non-type template class template<std::size_t N> Derived<N> which derives from some non-template base class Base:
class Base
{
public:
double some_value;
// Some methods and variables that do not depend on N
// I wish to keep these in a non-templated class
virtual const size_t get_N() = 0;
virtual ~Base() = default;
Base(double value): some_value {value} {};
};
template <std::size_t N>
class Derived: public Base
{
public:
double some_other_value;
// Some functions and variables, for which
// the types and actions depend on N
const size_t get_N() override
{
return N;
}
Derived(double value1, double value2): Base(value1), some_other_value {value2} {};
};
Now I have a function call_by_base(Base& my_base), which only uses member variables/functions declared in Base. The only exception to this, is a call to template<std::size_t N> void call_by_derived(Derived& my_derived). Since almost the entire function call_by_base is independent of the template parameter, I would prefer to keep this function non-templated.
I tried to achieve the above with implementations along the lines of:
template<std::size_t N>
void call_by_derived(Derived<N>& my_derived)
{
std::cout << "in call_by_derived" << std::endl;
// Methods that use the functions and variables in Derived.
}
void broken_call_by_base(Base& my_base)
{
std::cout << "in call_by_base" << std::endl;
// Manipulations independent of child
// type Derived<N>
auto derived = dynamic_cast<Derived<my_base.get_N()>&>(my_base);
call_by_derived(derived);
// Manipulations independent of child
// type Derived<N>
}
When I try to compile this code, I get error: expression ‘Base::get_N’ is not a constant-expression. I tried to resolve this error by trying to change different thing, both in my Base and Derived class. This was all without success.
I managed to get the following alternative to work:
void working_call_by_base(Base& my_base)
{
std::cout << "in call_by_base" << std::endl;
if(my_base.get_N()==2)
{
auto derived = dynamic_cast<Derived<2>&>(my_base);
call_by_derived(derived);
}
if(my_base.get_N()==3)
{
auto derived = dynamic_cast<Derived<3>&>(my_base);
call_by_derived(derived);
}
}
This is however very tedious, especially when N can take on many more values. Is there any way to get a function along the lines of broken_call_by_base working? That is: How can I downcast a non-template Base to a non-type template Derived<N>?
ps. Only object of the Derived<N> type will be created. This is the code in main to test:
int main()
{
Derived<3> test(1.0,2.0);
working_call_by_base(test);
broken_call_by_base(test);
call_by_derived(test);
}
It'll be best if you can use a virtual member function to avoid the if/else checks.
If that is not an option for some reason, use of a callback/plugin mechanism is the most appropriate.
You provide a mechanism in the Base-specific code base to allow other classes/functions/modules to register functions that are appropriate for the type they know about.
In the Base-specific code, you keep track of the registered functions using a key that is appropriate for Base.
In the Base-specific code, you check whether a function has been registered for the key. If it has, you call the function with the suitable arguments.
In the derived class specific code, you can downcast to the appropriate class. If the downcast succeeds, in most cases it should, you proceed to use the derived class.
This pattern strictly adheres to the Open-Closed Principle and is one of my favorite coding patterns.
In your case, the key is N.
Here's an example program that demonstrates the concept.
#include <iostream>
// Base.hpp
// #pragma once
#include <cstdint>
class Base
{
public:
double some_value;
// Some methods and variables that do not depend on N
// I wish to keep these in a non-templated class
virtual const size_t get_N() = 0;
virtual ~Base() = default;
Base(double value): some_value {value} {};
typedef void (*CallbackFunctionType1)(Base& b);
static void registerCallback(std::size_t N, CallbackFunctionType1 f);
};
void call_by_base(Base& my_base);
// Base.cpp
#include <map>
namespace BaseNS
{
using CallbackFunctionType1Map = std::map<std::size_t, Base::CallbackFunctionType1>;
CallbackFunctionType1Map& getCallbackFunctionType1Map()
{
static CallbackFunctionType1Map theMap;
return theMap;
}
}
void Base::registerCallback(std::size_t N, CallbackFunctionType1 f)
{
BaseNS::CallbackFunctionType1Map& theMap = BaseNS::getCallbackFunctionType1Map();
theMap[N] = f;
}
void call_by_base(Base& my_base)
{
std::cout << "In call_by_base" << std::endl;
BaseNS::CallbackFunctionType1Map& theMap = BaseNS::getCallbackFunctionType1Map();
BaseNS::CallbackFunctionType1Map::iterator iter = theMap.find(my_base.get_N());
if ( iter != theMap.end() )
{
iter->second(my_base);
}
}
// Derived.hpp
// #pragma once
template <std::size_t N>
class Derived: public Base
{
public:
double some_other_value;
// Some functions and variables, for which
// the types and actions depend on N
const size_t get_N() override
{
return N;
}
Derived(double value1, double value2): Base(value1), some_other_value {value2} {};
};
// Derived.cpp
// Register call back functions for Derived.
namespace DerivedNS
{
template <std::size_t N>
void call_by_derived(Derived<N>& derived)
{
std::cout << "In call_by_derived<" << N << ">" << std::endl;
// Use derived.
}
template <std::size_t N>
void call_for_derived(Base& my_base)
{
Derived<N>* d_ptr = dynamic_cast<Derived<N>*>(&my_base);
if ( d_ptr != nullptr )
{
call_by_derived(*d_ptr);
}
else
{
// Error.
}
}
bool registerCallbackFunctions()
{
// Register callbacks for as many values of N as needed.
Base::registerCallback(1, call_for_derived<1>);
Base::registerCallback(2, call_for_derived<2>);
Base::registerCallback(3, call_for_derived<3>);
Base::registerCallback(4, call_for_derived<4>);
Base::registerCallback(5, call_for_derived<5>);
return true;
}
bool dummy = registerCallbackFunctions();
}
int main()
{
Derived<1> d1(0, 0);
Derived<2> d2(0, 0);
Derived<10> d3(0, 0);
call_by_base(d1);
call_by_base(d2);
call_by_base(d3); // Does not go to call_by_derived.
}
Output:
In call_by_base
In call_by_derived<1>
In call_by_base
In call_by_derived<2>
In call_by_base
To start, I have something like this:
class Test {
std::vector<int> a, b;
void caller(...) { callee(...); }
void callee(...) { /* Do stuff with 'a' */ }
}
What I wanted is to have a function that does exactly the same as callee but for vector b. To do this there are two obvious solutions:
Pass vector a or b as argument. However, callee is a recursive function that can go for hundreds of calls, and passing the vectors as arguments would just be unnecessary overhead.
Copy the function callee and use vector b, which would be the best alternative, despite the fact that callee is quite a long function and I would have a lot of duplicate code.
Out of curiosity, I went looking for the templates part and I noticed that can be used for
lvalue reference type
pointer type
pointer to member type
So I tried to do this:
class Test {
std::vector<int> a, b;
void caller(...) { callee<a>(...); }
template <std::vector<int> &x> void callee(...) { /* Do stuff with 'x' */ }
}
but I get
error: use of ‘this’ in a constant expression
Is there any way to achieve this either with a reference or a pointer?
By the way, what I want can be seen as a function-scoped #define
Arrays and even tuples, but no love for good old pointers-to-members ?
class Test {
std::vector<int> a, b;
void caller(/*...*/) { callee<&Test::a>(/*...*/); }
template <std::vector<int> Test::*vec>
void callee(/*...*/) { /* Do stuff with `(this->*vec)` */ }
};
You cannot use a reference to a data member as a template argument: templates are compile-time, and the value of this is not known until runtime. In other words, you'd need a separate instantiation (separate binary code) for each runtime object of type Test.
What you can do is replace a and b with an array, and templatise callee by index into this array:
class Test {
std::array<std::vector<int>, 2> ab;
void caller(...) { callee<0>(...); }
template <size_t idx>
void callee(...) { /* Do stuff with 'ab[idx]' */ }
}
This way, you get only two instantiations of callee (one for 0 and one for 1), with the indexing done (or at least doable) at compile time.
Simply use a facade:
class Test {
std::vector<int> a, b;
void caller_a(...) { callee(a); }
void caller_b(...) { callee(b); }
void callee(std::vector<int> &a_or_b, ...) {
}
}
callee() will refer to its parameter, which will be passed in as one or the other class member.
In the same logic as #Angew's answer, you could also use std::tuple, and it's quite interesting as with tuple you can also use different kind of containers in your callee function :
class Test {
std::tuple<std::vector<int>, std::list<int> > ab;
void caller(...) { callee<0>(...); }
template <size_t idx>
void callee(...) {
...
auto aIt = std::get<idx>(ab).begin(); // gets either the vector or the list depending on template value
...
}
}
I want to call function either with default arguments or given by me, but default arguments are specified class private variables, simplified sample here:
Class::Something
{
public:
void setI(int i);
private:
void func(int i = this->i_default, j=this, k=this->k_default, l=this->l_default);
int i_default; // May be different for different instances.
int k_default; // May be different for different instances.
int l_default; // May be different for different instances.
}
So when i call func() it takes default i_variable or when i call func(4) it takes 4 argument without changing i_default value.
I know im doing something wrong couse i get error:
Error 1 error C2355: 'this' : can only be referenced inside non-static member functions or non-static data member initializer
is there some kind of way to achive such behaviour?
is there some kind of way to achive such behaviour?
Use function overload (Thanks #PiotrSkotnicki):
void func(int i);
void func() { func(i_default); }
You can declare i_default as const static (Thanks to #TartanLama).
const static int i_default=1;
Here is the working program.
You can also use function overloading. But this uses less code than function overloading!
The standard is quite clear about this. You explicitely cannot use this in the default parameter. You seem to be bound to use overloading for achieving this result:
void func(int i);
void func() { func(i_default); }
If you want to keep down the functions you could use a sentry that would allow func decide if it's to use the default. In the simpliest form:
void func(int* pi = NULL) {
int i = pi ? *pi : i_default;
// rest of the function
}
This method could be extended to use a helper class:
#include <cstdio>
template <typename C, typename T>
class Defaltable {
T val;
T C::* ptr;
public:
Defaltable(int C::* p) {
ptr = p;
val = 0;
}
Defaltable(T x) {
val = x;
ptr = NULL;
}
T fetch(C* p) {
return ptr ? p->*ptr : val;
}
};
class Foo {
int i_default;
public:
Foo(int dflt) {
i_default = dflt;
}
int func(Defaltable<Foo, int> x = &Foo::i_default) {
return x.fetch(this);
}
};
int main()
{
Foo c(42);
printf("%d\n", c.func(1));
printf("%d\n", c.func());
}
I'm having a problem with correctly building a container that stores class specimens of different types that are all inheritors of a single abstract class. The register(the container) stores a pointer to the array of these specimens, that has the type of the abstract class. Whenever I try to access data contained in the specimens I only succeed in retrieving parts that can be found in the base class too. For example, an overloaded << used on the register that contains elements of all three inheritors, will only write the abstract class parts on screen, and will neglect anything not present there. Now I don't really know if the problem is with printing out the otherwise correctly stored elements, or the storing is already done in an inappropriate form, so that would be my question: how should this be done properly? Here's the code:
class Register{
private:
int elementNum;
type * pData;
friend std::ostream &operator<<(std::ostream & os,const Register &v);
};
class type{
int a;
int b;
};
class type2: public type{
int c;
int d;
};
The other two inheritors behave the same way as the type2. Here's a part of main:
int main ()
{
type2 A1(1,2,3,4);
type3 D1(4,5,6,7,8);
type4 H1(9,10,11,12,13);
std::cout<<A1<<D1<<H1<<endl;
Register R1;
R1.Add(0,A1);
R1.Add(1,D1);
R1.Add(2,H1);
R1.Display();
R1.MaxLength();
std::cout<<R1;
return 0;
}
Operator << on the register:
std::ostream &operator<<(std::ostream & os,const Register &v){
for(int i=0;i<v.elementNum;i++)
{
os<<v.pData[i]<<endl;
}
return os;
}
Only using the << operator or a function from the register ends in this problem.
Edit: Implementation of the Add function:
void Register::Add(int position,type& T){
if(position<0||position>elementNum+1)
return;
type *pTemp = new type[elementNum+1];
if(elementNum==0)
{
pTemp[0]=T;
delete[]pData;
pData=pTemp;
}
else
{
for(int i=0,j=0;j<elementNum+1;i++,j++)
{
if(position!=j)
pTemp[j]=pData[i];
else
{
i--;
pTemp[j]=a;
}
}
delete[]pData;
pData=pTemp;
}
elementNum++;
}
You can only access public members common to the base class, or virtual method available from the base, polymorphically.
Furthermore, you can only access virtual methods through pointers/references, and you generally can't store different class instances contiguously like you try to do with pData.
If you make a virtual std::ostream &type::dump(std::ostream &os) member method and override is in type2, etc., you can make each overriddinen method show content particular to its sub-type.
struct type {
virtual ostream &dump(ostream &os) {
os << a << " " << b << " ";
return os;
}
int a;
int b;
};
struct type2 : type {
// Can use parent implementation AND use subtype-specific members:
ostream &dump(ostream &os) override {
type::dump(os);
os << c << " " << d << " ";
return os;
}
int c;
int d;
};
// This class needs new "void Add(int pos, type &)" logic.
struct Register {
int elementNum;
type *pData; // next hint: this is almost definitely not what you want.
type **pda; // probably better (need to use new/delete to make types)
};
ostream &operator<<(ostream &os, Register const &v) {
for (int i = 0; i < v.elementNum; ++i) {
// Calls proper virtual method for each instance.
v.pData[i].dump(os); // XXX probably broken too
v.pda[i]->dump(os); // should look more like this
os << endl;
}
}
type *pTemp = new type[elementNum+1];
This allocates an array of objects with type type. An object can never change its type, and you cannot replace an element of an array, only modify it. So your Register object never contains objects of any derived classes at all, only those objects with the base class type.
To get an array of heterogeneous objects the hard way, you would need an array of pointers:
type **pTemp = new (type*[elementNum+1]);
To do it the right way, you would shun arrays and raw pointers, and instead use containers and smart pointers:
class Register {
public:
const type& get(int pos) const;
type& get(int pos);
void Add(int pos, const type& obj);
void Add(int pos, std::unique_ptr<type>&& ptr);
// ...
private:
std::vector<std::unique_ptr<type>> m_data;
};
But either way, what pointers do you put in it from your function Add?
void Register::Add(int position,type& T);
Probably not the address &T of the passed reference. Who knows when that object will be destructed. And new type(T) is no good either - it just creates an object of the base type, ignoring the actual type of T. So you'll probably want a clone() method, sometimes called a "virtual copy constructor":
class type {
public:
using pointer = std::unique_ptr<type>;
virtual ~type();
virtual pointer clone() const;
};
type::pointer type::clone() const {
return pointer(new type(*this));
}
type::pointer type2::clone() const {
return pointer(new type2(*this));
}
Above I put in two overloads of Add(). The object-passing version goes like:
void Register::Add(int pos, const type& obj) {
if (pos<0)
return;
if (pos >= m_data.size())
m_data.resize(pos+1);
m_data[pos] = obj.clone();
}
The other version could be useful if you happen to have a type::pointer already, rather than just an object. With this overload you can just move it into the Register, without needing to clone() anything.
void Register::Add(int pos, type::pointer&& ptr) {
if (pos<0)
return;
if (pos >= m_data.size())
m_data.resize(pos+1);
m_data[pos] = std::move(ptr);
}
It's quite hard to explain what I'm trying to do, I'll try: Imagine a base class A which contains some variables, and a set of classes deriving from A which all implement some method bool test() that operates on the variables inherited from A.
class A {
protected:
int somevar;
// ...
};
class B : public A {
public:
bool test() {
return (somevar == 42);
}
};
class C : public A {
public:
bool test() {
return (somevar > 23);
}
};
// ... more classes deriving from A
Now I have an instance of class A and I have set the value of somevar.
int main(int, char* []) {
A a;
a.somevar = 42;
Now, I need some kind of container that allows me to iterate over the elements i of this container, calling i::test() in the context of a... that is:
std::vector<...> vec;
// push B and C into vec, this is pseudo-code
vec.push_back(&B);
vec.push_back(&C);
bool ret = true;
for(i = vec.begin(); i != vec.end(); ++i) {
// call B::test(), C::test(), setting *this to a
ret &= ( a .* (&(*i)::test) )();
}
return ret;
}
How can I do this? I've tried two methods:
forcing a cast from B::* to A::*, adapting a pointer to call a method of a type on an object of a different type (works, but seems to be bad);
using std::bind + the solution above, ugly hack;
changing the signature of bool test() so that it takes an argument of type const A& instead of inheriting from A, I don't really like this solution because somevar must be public.
EDIT:
Solution (1) is:
typedef bool (A::*)() mptr;
std::vector<mptr> vec;
vec.push_back(static_cast<mptr>(&T::test));
std::vector<mptr>::iterator i;
for(i = vec.begin(); i != vec.end(); ++i) {
(a .* (*i))();
}
I'm not sure the static cast is safe.
The cleanest solution is the last one you suggest, make test a (pure) virtual function in A:
virtual bool test(const A& value) = 0;
If you're bothered with making somevar public keep it private and supply only a public get function:
int getvar() const {return somevar;}
You are trying to call B and C methods on an A. Don't do that.
You need to create actual instances of B and C, store pointers to them in a vector<A*> and, during iteration, call a pure virtual test() member function defined in A (which B::test and C::test will override).
Add "virtual bool test() = 0;" in the definition of A.
Then you can do the following in your loop:
ret = (ret && i->test());
BTW: "&=" does a "bitwise and" and you probably want the logical and to be performed (&&).
Also: the instances of B and C you put pointers to in your vector all contain copies of the inherited variable, they are all independant instantiations of that variable.
I think your code, as shown here, is pretty flawed. Think more about what it is you want to actually achieve?
Do you want to run a multiplicity of boolean tests on a single variable and see if it matches all of them?
Or is each contraint really to be tested against its own variable and you want to get the "boolean and" of all those independent tests?
This is the cleanest solution so far. It uses static:
struct A {
int somevar;
};
struct B {
static bool test(const A& a) {
return (a.somevar == 42);
}
};
std::vector<bool (*)(const A&)> vec;
template<typename T>
void push(const T&) {
vec.push_back(&T::test);
}
The simple solution:
Change class A to:
class A {
public:
virtual bool test() const = 0;
protected:
int somevar;
// ...
};
Now, I need some kind of container that allows me to iterate over the elements i of this container, calling i::test() in the context of a.
typedef std::vector<A*> ItemList;
ItemList items;
for(ItemList::const_iterator i = items.begin(); i != items.end(); ++i)
{
if((*i)->test())
; // ???
}
So I'm wondering what the OP wants to do that this doesn't...