Here is an abstraction of my problem.
I want to develop something like this.
class Base {
}
template<typename T>
class TypedBase : Base {
f(const T& input);
}
Now I Want to access the "family" of classes TypedBase via a base pointer and call f.
Something like this
Base* base_ptr;
if (condition) {
base_ptr = new TypedBase<double>();
} else {
base_ptr = new TypedBase<int>();
}
// Int and double are just examples to get the idea
// Then I Want to call
base_ptr->f(4);
This won't compile.
I tried to add an empty virtual function f() to base hoping that vtable would take care of calling the right f() vs. f(T& input) at run time but again didn't work like:
class Base {
virtual f() = 0;
}
So how do you do that? in general I want to have a pointer to a generic TypedBase that allows me to call f(...) via a generic pointer to the family. Any thoughts?
Of course I could do this:
class Base {
// Repeat for every typename
virtual f(int& x) = 0;
virtual f(double& x) = 0;
}
and then each TypedBase will only implements one of them thus I will still get type safety at run time without doing dynamic checking myself in the code. However, If I have N functions to call and M types to work with, then I will have to add M*N abstract functions to the Base class. Any better solution?
You must static_cast (if you know the real type) or dynamic_cast (if you need to check if cast succeeded) the base pointer to right class. If you know what you are passing to method, casting to type that takes that argument should not be a problem. Also casting should work in a template method with right template type.
Does following compile?
template <typename T>
void callF(Base *p, T input) {
TypedBase<T> *tp = dynamic_cast<TypedBase<T>*>(p);
if (tp) tp->f(input);
// else throw exception or call some Base method or return error or...
}
Or less safe, just do:
static_cast<TypedBase<int>*>(base_ptr)->f(1);
Related
I have a templated class, say:
template <class C, int I>
class A {
A() {};
someMethod(){...};
};
Now, let's say I have several objects of this class used in my code with different template parameters (classes B,C, and D are some defined classes):
A<B, 1> object1;
A<C, 2> object2;
A<D, 3> object3;
What I would like to have is a function that returns one of these three objects based on some logic:
A getObject(){
if(condition1)
return object1;
else if(condition2)
return object2;
else
return object3;
}
However, when I try to compile this, I get error: invalid use of template-name ‘A’ without an argument list, which makes sense, but I don't know which arguments should I provide?
For instance, if I put
A<B, 1> getObject(){
return object1;
}
then I can only return object1, but not object2 or object3.
Ultimately, my goal is to have something like:
A obj = getObject();
...
lot's of code where obj.someMethod() get's called a lot
...
This is simpler to reason about if you think of A<B,1>, A<B,2> and A<B,3> as three completely unrelated classes Foo, Bar and Moo, which they bascially are. Now try to find a way to return those from a single method: You need a common base or any or variant ... runtime polymorphism: The same method returns an object and you do not care about the type as long as it implements an interface.
class A_base {
virtual void someMethod() = 0;
virtual ~A() {}
};
template <class C, int I>
class A : public A_base {
A() {}
void someMethod() override {/*...*/}
};
std::unique_ptr<A_base> getObject() {
//...
}
I assumed that condition is only known at runtime. Otherwise the whole quesiton is moot, because if it is know at compile time then you could simply make getObject a template that returns only the one type determined by the condition.
Your return statements on the getObject function each have a different type (Templates instanced with different classes have different types). Functions can only return a single type so returning the templates as they are is not a possibility.
So the solution needs all the templates to share a common type. To accomplish this you would need to create a base class with a virtual someMethod call, make every template inherit from this base class implementing someMethod and return a pointer to base class from the getObject function (Being careful not to narrow the derived class returned). Then you can leverage virtual dispatch to call the appropriate someMethod.
A is not a type and therefore you cannot declare it as a return value. And A<B, 1>, A<C, 2> and A<D, 3> are all different types. What you can do, however, that doesn't require changing A is to call a function object with the object instead of returning it. Your function would then become
template <typename F>
void getObject(int i, F f) {
if (i == 1) {
f(object1);
} else if (i == 2) {
f(object2);
} else if (i == 3) {
f(object3);
}
}
and you would use it like
getObject(3, [](auto x) {
std::cout << "Call someMethod: " << x.someMethod() << std::endl;
});
Having auto x in the function argument list is only available in more recent C++ versions. If your C++ version does not support that, you would have to declare a class and implement the operator() for the types.
I try to override the base class function but because I have templatised its child/derived/sub class I can't override the function depending on which type I instantiate the template with.
struct BaseType
{
virtual double getPropertyValue() = 0;
};
template <typename T>
struct NumberType : BaseType
{
T propertyValue;
T getPropertyValue() override { return propertyValue; } // I would like this to return whatever T is.
};
int main()
{
std::vector<BaseType*> vectr;
NumberType<double> doubleType; // This is fine, overrides the base function
NumberType<int> intType; // Has no overrider, won't compile
}
So I thought maybe I could templatise also the Base class, so that the base class function returns T also. But if I do this I won't be able to keep them in a container or point to them, because they'll all be of different Base< type> types.
I also thought about templatising Base and having it inherit from an even higher parent (which isn't templatised), but I run into the same problem.
Is there any way around this?
You can do this if the return value T is covariant with the return value of the pure virtual function. But sadly a T will not, in general, be covariant with a double.
Accepting that you're mixing up static and dynamic polymorphism techniques, which might be a design flaw, you could define
struct Cov {};
with
struct BaseType
{
virtual Cov& getPropertyValue() = 0;
};
Then,
template <typename T>
struct NumberType : BaseType
{
T propertyValue;
T& getPropertyValue() override { return propertyValue; }
};
where T is a child class of Cov: this relationship means that T& is a return type that's covariant with Cov&, and so compilation will succeed. Doing it this way also obviates a value copy of T being taken. You might also find it convenient to build conversion operators for the various Ts that end up getting built that have primitive type return values.
You can also introduce const reference return types to suit the exact requirements.
BaseType has a contract that is binding for all its descendants. It says says that getPropertyValue returns double. NumberType doesn't get to modify the contract, it's set in stone.
Let's pretend the contract is not there.
BaseType& base = BaseContainer.getSome();
// base can be NumberType<complex> or
// or NumberType<tensor<double,4,4,4>> or NumberType<padic<5>>
// or a type that is not even thought of yet
// as of now.
what = base.getPropertyValue(); // how should 'what' be declared?
There's no way to use the result of base.getPropertyValue() if we don't know what it is.
Making the return type covariant doesn't really help. It just shifts the problem from BaseType to whatever base class BaseType::getPropertyValue() returns.
You need to come up with a usable interface of BaseType and stick to it in all descendant classes.
I'd like to cast a base class pointer to a derived one in order to take advantage of some methods unique to the derived class. Here's an Ideone of a simple example that works:
template<typename A>
class Base {};
template<typename A, typename B>
class Derived : public Base<A> {
public:
void doSomething() {}
};
int main() {
Base<int>* foo = new Derived<int, double>;
static_cast<Derived<int, double>*>(foo)->doSomething();
return 0;
}
Now, the problem is that my foo is actually a member of a templated class,
template<typename A>
class Container
{
public:
Base<A>* foo;
};
and at the time I cast, I don't know what A is:
int main() {
Container<int> container;
container.foo = new Derived<int, double>;
// a lot of code later...
static_cast<Derived< /* ??? */ , double>*>(container.foo)->doSomething();
return 0;
}
Then I thought this might be possible if I could somehow store what A is in my base class, like
template<typename A>
class Base
{
public:
static type template_type = A; // made-up syntax
};
so that I can refer to it like
static_cast<Derived<container.template_type, double>*>(container.foo)->doSomething();
but according to this question it's not possible to store types in C++.
How do I achieve this cast without knowing A?
That is, how do I cast a specialized base pointer to a derived pointer that specializes on an additional template parameter? In less technical terms, I just want to take a Base pointer and tack on the other specialization necessary to form the Derived pointer.
Usually it is not wise to do an up-cast and there is usually a better design that you may use to avoid the need of up-cast at all, but if you really need it, then you may use dynamic_cast to do this.
this operator try to convert from one type to another type dynamically and if conversion is not possible, it will return nullptr. But remember that it only work for polymorphic types(types that have at least one virtual function) so in this case your Base class must be polymorphic(since you are holding a pointer to base class, you possibly need a virtual destructor to allow delete to work on base pointer and this make Base a polymorphic class).
But to remember a type in C++, you have 2 options:
Use typedef:
You may use typedef to hold type information in the class:
template< class A >
class my_class
{
public:
typedef A input_type;
};
template< class T >
void do_something(T const& t)
{
typename T::input_type n;
do_something_on_input_type(n); // possibly overloaded for different input types
}
this approach is really fast and have no overhead in runtime, but you can use it only in cases when you want to do something in compile time. and if the type of pointer is not determined until runtime this approach is not useful.
Use std::type_info
Using this you can actually hold type information with the class:
class Base { virtual std::type_info const& get_type() const = 0; };
class Child : public Base
{
virtual std::type_info const& get_type() const { return typeid(Child);
void child_specific_function() { /**/ }
}
class ChildOfChild : public Child
{
virtual std::type_info const& get_type() const { return typeid(ChildOfChild); }
// ...
};
void do_something(Base* base)
{
if (base->get_type() == typeid(Child))
{
static_cast<Child*>(base)->child_specific_function();
}
}
This sound really interesting but, it is only useful when you know exact type of the object and it does not work for derived types, so this approach work for Child but not for ChildOfChild
I have a virtual function that is implemented in a base class A.
This function has a loop in it. A derived class B is available but does not override the virtual function as the code is the same for any derived class.
Well, however, I need an additional condition check inside that virtual function (local_policy) that should be called depending on class type (base or derived).
Now, I could implement another virtual member function and override it in the derived class however as the call happens inside of a loop the virtual overhead should be minimized, so I thought I rather use a function template and specialize it for any derived classes.
Now the problem is that I am passing *this pointer to the function template from within foo() and the specialization is never called.
Is the this pointer in this certain case of type A instead of B? I would have guessed it is not and that my specialised function template would be called.
I appreciate any help!
template < typename T >
bool local_policy(const T* mtype) { return true; }
class A
{
public:
virtual void foo()
{
for(..) {
if(local_policy(this)) //This will call the non-specialised template! Why?
{ /* do something */ }
}
}
/* [...] */
}
class B : public A
{
/* [...] */
//foo() is not overridden here
}
//Specialize the function template for class B
template <>
bool local_policy(const B* mtype) { return false; }
main()
{
B* test = new B; if(!B) return;
test->foo();
}
Thanks in advance!
Best
P.S.: I also tried some C++11 using a normal function and a global template with std::enable_if to only enable if it is a derived class. Doesn't matter, also that one is not called as I expected. :-/
C++ does not allow dynamic dispatch based on argument types -- function overload resolution is always based on the static type of the expression. In your example, the static type of this with always be A *, even when it points at a B, so your specialized function will never be called.
If you want dynamic dispatch, you must use a virtual function, and you can only dynamically dispatch based on the this argument, never any other arguments. If you're worried about the overhead, you can hoist the dynamic call out of the loop and only call it once:
virtual bool local_policy() { return true; }
virtual void foo() {
bool policy = local_policy();
for (..) {
if (policy) {
/* do something */
}
}
}
The compiler can't ever do this optimization on its own, since it doesn't know that you'll never define a derived class that overrides the local_policy function with something that has side effects...
EDIT:
In the following code container::push takes an object of type T that derives from base as argument and stores in a vector a pointer to the method bool T::test().
container::call calls each of the stored methods in the context of to the member object p, which has type base, not T. It works as long as the called method does not refer to any member outside base and if test() is not declared virtual.
I know this is ugly and may not be even correct.
How can I accomplish the same thing in a better way?
#include <iostream>
#include <tr1/functional>
#include <vector>
class base {
public:
base(int v) : x(v)
{}
bool test() const { // this is NOT called
return false;
}
protected:
int x;
};
class derived : public base {
public:
bool test() const { // this is called instead
return (x == 42);
}
};
class container {
public:
container() : p(42)
{}
template<typename T>
void push(const T&) {
vec.push_back((bool (base::*)() const) &T::test);
}
void call() {
std::vector<bool (base::*)() const>::iterator i;
for(i = vec.begin(); i != vec.end(); ++i) {
if( (p .* (*i))() ) {
std::cout << "ok\n";
}
}
}
private:
std::vector<bool (base::*)() const> vec;
base p;
};
int main(int argc, char* argv[]) {
container c;
c.push(derived());
c.call();
return 0;
}
What you are doing with your "boost::bind" statement is to call derived::test and pass "b" as a "this" pointer. It's important to remmember that the "this" pointer for derived::test is supposed to be a pointer to a "derived" object - which is not the case for you. It works in your particular situation since you have no vtable and the memory layout is identical - but as soon as that will change, your program will likely break.
And besides, it's just plain wrong - ugly, unreadable, bug-prone code. What are you really trying to do?
[Edit] New answer to the edited question: You should use boost::bind to create a functional closure, that wraps both the object & the member function in a single object - and store that object in your collection. Then when you invoke it, it is always reliable.
If you can't use boost in your application... well, you could do something like boost::bind yourself (just look on how it is done in boost), but it's more likely that you'll get it wrong and have bugs.
To the updated question:
Calling a derived member function on a base object is Undefined Behavior. What you are trying to achieve (code) is wrong. Try to post what you need and people will help with a sensible design.
What you are doing is not correct, and in the simple example it will work, but might just raise hell (one of the possibilities for undefined behavior) in other cases.
Since base::test and derived::test are not virtual, they are two different member methods, so for simplicitly I will call them base::foo and derived::bar. In the binder code you are forcing the compiler into adapting a pointer to bar that is defined in derived as if it was actually defined in base and then calling it. That is, you are calling a method of derived on an object or type base!!! which is undefined behavior.
The reason that it is not dying is that the this pointers in base and derived coincide and that you are only accessing data present in the base class. But it is incorrect.
When you declare base::test virtual, you get the correct behavior: your most derived object in the hierarchy is base, the compiler will use the virtual dispatch mechanism and find out that base is where the final overrider for test is found and executed.
When you declare only derived::test as virtual (and not base) the compiler will try to use an inexistent virtual dispatch mechanism (usually a vtable pointer) in the handed object and that kills the application.
At any rate, all but the virtual base::test uses are incorrect. Depending on what your actual requirements are, the most probably correct way of doing it would be:
class base {
public:
virtual bool test() const;
};
class derived : public base {
public:
virtual bool test() const; // <--- virtual is optional here, but informative
};
int main()
{
derived d; // <--- the actual final type
base & b = d; // <--- optional
if ( std::tr1::bind( &base::test, std::tr1::ref(b))() ) {
// ...
}
}
Note that there is no cast (casts are usually a hint into something weird, potentially dangerous is hiding there), that the object is of the concrete type where you want the method to be called, and that the virtual dispatch mechanism guarantees that even if the
bind is to base::test, as the method is virtual, the final overrider will be executed.
This other example will more likely do funny things (I have not tried it):
struct base {
void foo() {}
};
struct derived : base {
void foo() {
for ( int i = 0; i < 1000; ++i ) {
std::cout << data[i];
}
}
int data[1000];
};
int main() {
base b;
std::tr1::bind((void (base::*)()) &derived::foo, std::tr1::ref(b))();
}