Assign template<derived> to a template<base> variable [duplicate] - c++

This question already has answers here:
Is Template of derived object a subclass of template of base type
(5 answers)
Closed 8 years ago.
I have a template class that replaces direct construction of objects with just storing them for future purpose.
template<typename T>
typedef struct Construction{
int arg;
} Construction;
Now I want to pass a std::vector< Construction< Base > > to a function that should then call the constructors of every Element with the given argument.
This works when I only use the base type, but as soon as I try to mix base and derived types, problems emerge:
Construction<Base> construct = Construction<Derived>(5);
This won't work, while a regular assignment like Base& b = Derived(5); does.
Why does this not work?

This sounds like a lazy factory pattern. As you say in a comment, Constr<Base> does not hold enough information to construct a Derived. So when storing in a vector, you should use pointers rather than values. If you are willing to use the free store for the final objects, one solution is the following:
struct Base { int x; };
struct Derived : public Base { Derived(int x) : Base{x} { } };
template<typename T>
struct Constr;
template<>
struct Constr<Base> {
virtual std::unique_ptr<Base> make() const = 0;
};
template<typename T>
struct Constr : Constr<Base> {
int arg;
Constr(int arg) : arg{arg} { }
std::unique_ptr<Base> make() const override
{
return std::make_unique<T>(arg);
}
};
int main() {
Constr<Derived> a{5}, b{2}, c{8};
std::vector<Constr<Base>*> v{&a, &b, &c};
// later...
std::vector<std::unique_ptr<Base>> u;
for (auto& i : v)
u.push_back(i->make());
for (auto& i : u)
std::cout << i->x << " "; // 5 2 8
}
For this to work, we now make Constr<Derived> derive Constr<Base>. So we can use pointers/references to such objects following the same rules as pointers/references to Base/Derived, without defining any special constructors.
Note the forward declaration of Constr: this is needed because specialization Const<Base> needs to be defined before the general template; in turn, this is needed because the latter implicitly instantiates the former (by deriving it).
I cannot think of a simple solution without the free store, though. The only possibility is to use a raw memory buffer, either as a data member of Constr<Base>, or passed as an argument to make(). But this needs some work and will always have an upper bound on the size of Derived. Or, we could automatically choose between stack/free store depending on object size; this is generic but needs even more work.

It does not work, because instantiations of class templates are not related via a subclass-superclass relationship, even if the types, used in the instantiation are.
In many cases you can solve the problem, by providing a constructor template and/or assignment operator template to your original template, like:
struct Base {
int x;
};
struct Derived : public Base {
int y;
};
template<typename T>
struct Constr {
T t;
Constr() = default;
template<typename U> Constr(const Constr<U> &a) : t(a.t) {}
};
int main() {
Constr<Derived> a;
Constr<Base> b = a;
// Constr<Derived> c = b; // error, as it should
}

Related

Calling function in derived class from base class of crtp with generic return type

I am creating a library which allows the user to store a pointer and later retrieve the pointer.
I have a class which stores the pointer of a generic type.
template <typename generic_type>
class A
{
public:
A() {}
A(generic_type *value) : data(value) {}
generic_type *getData()
{
return data;
}
private:
generic_type *data;
};
I want to also store the instances of these class template in a vector, so i inherited from a base class.
class B
{
};
template <typename generic_type>
class A : public B
{
...
};
class test_class
{
};
std::vector<B *> list;
// -------- example -------
// test_class *test = new test_class();
// list.push_back(new A<test_class>(test));
// list.push_back(new A<test_class>(test));
// list.push_back(new A<test_class>(test));
When retrieving from the list i will get a pointer to base class.
To call the functions in derived class A, it will have to be cast.
// example
B *bp = list.at(0);
A<test_class> *ap = static_cast<A<test_class> *>(bp);
I do not want the user to manually have to cast the base pointer themselves, but be able to call the getData() function in A which will return the actual data based on the generic_type.
// preferred API usage
B *bp = list.at(0); // they will get B pointer in another way but shown here for simplicity
test_class *t = bp->getData();
Looking around for calling child function from parent class, i came upon CRTP, which allowed me to call the function in A;but now i am unable to store it in a vector as B will be templated. So i derived B from another class referencing code from this post.
This allowed me to store it in a vector but i cant seem to find a way to call the function with generic return type and return it.
class C
{
public:
virtual void func() = 0;
};
template <typename derived>
class B : public C
{
public :
void func() // cant change to templated return type as virtual function cant be templated
{
derived *p = static_cast<derived *>(this);
p->getData(); // how to return the value from this ?
}
};
template <typename generic_type>
class A : public B<A<generic_type>>
{
...
};
std::vector<C *> list;
// -------- example -------
// this allows me to do
C *cp = list.at(0);
cp->func(); // will call getData() indirectly
// but am unable to get the returned data
I am not familiar with newer features or design patterns as i have not used c++ for a few years.
Is it possible to get the returned data? or is there a different method or pattern i could use to achieve the desired API usage scenario?
You will never get around the fact that the user has to specify which type they expect to receive. The compiler needs to know at compile-time what the return type of getData will be, so you have to decide at compile-time which concrete A instantiation you are operating on.
However, there is a way to make this "specifying the type" more convenient than a manual static cast: Provide an implicit conversion in B to any pointer.
class B
{
public:
virtual ~B() = default;
template<class T>
operator T*();
};
template <typename generic_type>
class A : public B
{
// ...
};
template<class T>
B::operator T*()
{
A<T>* a = dynamic_cast<A<T>*>(this);
if (!a)
return nullptr;
return a->getData();
}
// Usage:
std::vector<std::unique_ptr<B>> list;
list.emplace_back(new A<test_class>);
list.emplace_back(new A<int>);
list.emplace_back((A<double>*)nullptr);
test_class* out1 = *list[0]; // Returns the correct ptr
test_class* out2 = *list[1]; // Returns nullptr (incorrect type)
double* out3 = *list[2]; // Returns nullptr (data value is null)
https://godbolt.org/z/NT1AF8
This conversion operator assumes that, when we try to convert some object x from a B to some T*, that the dynamic type of x is A<T*>. It attempts the down-cast and returns getData() if it succeeds, or nullptr otherwise.
This works just fine in principle, you should however be aware that implicit conversions are better used sparingly or not at all - they can lead to very surprising behavior. You might also want to (SFINAE-)guard against someone creating an A<A<something>> or A<B>, because that sounds like a headache.
Getting it to work with cv specifiers (i.e. const/volatile) will require some more work (including specifying whether A<const int> should be a thing or not).
You could also take the middle route between manual static_cast and the implicit conversions above by writing a free accessor function like
template<class T>
T* getData(B& b)
{
// See operator T* implementation above.
}
which would be used like double* y = getData<double>(x);. I would prefer this solution for a library interface.

C++ class with template member that constructs template member with arbitrary template arguments

I'm not sure why the following code block compiles and works even though the semantics implied by the template syntax are different. Class A accepts a template type Data and contains a member data of template type Data. It also has a constructor that accepts an instance of Data by value and instantiates the member data with the assumed copy constructor. Another class C has an arbitrary constructor that takes a pointer to some arbitrary class B and stores it as member foo. When Data in A is templated as type C and an A<C> instantiated with arguments that the constructor for C accept (namely, a pointer to a B) one would expect a compiler error because A has not been told how to handle arbitrary arguments and pass them to the Data constructor. It has only been told to use the copy constructor of Data with an existing instance. However, this code compiles with clang and c++11 and prints true. I'm assuming this is a compiler bug, not a feature, but perhaps I'm missing something about how C++ templates work? I'm also curious about the correct syntax for this functionality is, (to pass arbitrary template parameters to the constructor for A and forward them to the constructor for type Data) as that is my actual intent.
#include <iostream>
template<typename Data>
struct A {
Data data;
A(Data data_) : data(data_) { }
};
struct B {
B() { }
};
struct C {
B* foo;
C(B* foo_) : foo(foo_) { }
};
int main() {
B foo;
A<C> thing = A<C>(&foo);
std::cout << (thing.data.foo == &foo) << std::endl;
return 0;
}
EDIT:
correct way is parameter packing
template<typename Data>
struct A {
Data data;
template<class ... Args>
A(Args... args) : data(std::forward<Args>(args)...) { }
};
struct B {
B() { }
};
struct C {
B* foo;
C(B* foo_) : foo(foo_) { }
};
int main() {
B foo;
A<C> thing = A<C>(&foo);
std::cout << (thing.data.foo == &foo) << std::endl;
return 0;
}
The reason your code compiles is because your constructor for struct C is not flagged as explicit. In effect, A<C> object expects a C object in its constructor. But you provide a pointer to b instead. Since none of your single parameter ctors are flagged as explicit, it is legal for the compiler to choose an appropriate conversion from input parameter to the desired parameter.
Usually static code analyzers will flag this as undesirable as you don't ever want automatic or unexpected conversions of this sort. So you really should flag all single parameter ctors with the explicit keyword.
https://en.cppreference.com/w/cpp/language/explicit

Passing std::vector of derived type where a std::vector of base type is expected

I have a base class:
class Member
{
....
}
and a derived class, like this:
class Mine_sweeper : private Member
{
....
}
Then I have a container:
class Population
{
public:
std::vector<Member>& m_members;
Population(std::vector<Member>& members);
}
When I use Population's constructor with a vector of Members it compiles OK. But if I try to link Population's m_members with a vector of Mine_sweepers, complier throws an error.
std::vector<Member> members;
Population pop(members); // this compiles OK
std::vector<Mine_sweeper> sweepers;
Population pop(sweepers); // but here I get an error
main.cpp(23): error C2664: 'Population::Population(std::vector &)' : cannot convert parameter 1 from 'std::vector' to 'std::vector &'
Vector of Mine_sweepers is not a "kind of" vector of Members, even when Mine_sweeper is a "kind of" Member. You can not use vector<Derived> in place of vector<Base>.
Use vector<unique_ptr<Member>> instead of vector<Member> AND vector<Mine_sweeper>. This enables you to have heterogeneous Population of Members (i.e. Mine_sweepers and other Member sub-types, at the same time).
Alternatively, convert the Population class to a class template:
class Population<T>
{
public:
std::vector<T>& m_members;
Population(std::vector<T>& members);
}
This way, one Population instance may only contain one type of Members.
You can't. Not as is. This is because std::vector<B> is not derived from std::vector<A>, regardless of the fact that B is derived from A.
But wait ... let us simplify your problem with a minimal example:
struct A {};
struct B : A {};
void f(std::vector<A> const&) {}
int main()
{
std::vector<A> vecA;
std::vector<B> vecB;
f(vecA);
f(vecB); // error
}
Here, unlike in your sample code, B publicly inherits from A. You still can't give a std::vector<B> const& to a function expecting a std::vector<A> const& because there exists no implicit conversion from std::vector<B> to std::vector<A>.
In the following case, one can send a B const& where a A const& is expected because C++ provide an implicit conversion from reference to a derived type to a reference to a base type.
struct A {};
struct B : A {};
void f(A const&) {}
int main()
{
A alice;
B bob;
f(alice);
f(bob);
}
A solution is to provide an explicit conversion using the existing implicit conversion from B to A:
struct A {};
struct B : A {};
class Container
{
std::vector<A*> _items;
public:
template<class T>
Container(std::vector<T> v)
: _items(v.begin(), v.end())
{}
// other stuff, see rule of 5
};
int main()
{
std::vector<A*> vecA;
std::vector<B*> vecB;
Container contA(vecA);
Container contB(vecB);
}
Once you have a basic working conversion, you need to figure out how to handle memory ownership with std::unique_ptr, std::shared_ptr and std::weak_ptr.
The constructor for the Population class takes an argument to a vector holding an array of Member class. You're right that you can pass a derived class to something that takes the base class as argument, or upcast from derived to base, but what you're doing here is different. You're not sending a derived class to a function taking a base class argument, you're sending a different unrelated type altogether, you're sending an std::vector< typeA> to something that wants std::vector< typeB>.
When you create std::vector< int> at compile time it will create the vector class with all the specific details specific to how it for example iterates over the ints etc. This is an array or "ints". Would it make sense to pass it to a function that takes an array of doubles? Then the function is doing work on doubles, for example to move to the next double it might move forward 8 bytes instead of 4, it would be doing the wrong thing.
You would have to make two versions of the Population class manually or use templates to do it. Edit: See YSC's answer, he templates the constructor
Or, you probably want one vector/array which could contain both types of class, Base and Minesweeper. To do this you can't store the objects themselves in the array, because the two types of object might be different size and have different members. So you can have a vector of pointers to the Base class. Then the polymorphism part is for identifying, when you dereference one of those pointers, whether you're pointing to a Base or a Minesweeper. The virtual function is for calling the right function depending on which object it is.
You can't just pass a vector of derived class objects to a function who need a vector of of base class objects, because vector is not derived from vector.
You can do some covertion, get a slice of vector, like this:
vector<Base> converted(base_vec.begin(), base_vec.end());
But this is not efficient, if the calling method is in your control, you can just use template:
template <typename T>
void foo(const vector<T>& v) {
v[0].bar(); // do something with v
}
If you do not want other types those have bar but is not the derived class of Base, you can use std::enable_if:
template<typename T, typename Enable=std::enable_if<std::is_base_of<Base, T>::value>>
void foo(const std::vector<T>& v) {
v[0].bar(); // do something with v
}
Whole program can compile with gcc main.cc -std=c++11:
#include <vector>
class Base{
public:
void bar() const {}
};
class Derived: public Base{
};
template<typename T, typename Enable=std::enable_if<std::is_base_of<T, Base>::value>>
void foo(const std::vector<T>& v) {
v[0].bar();
}
int main() {
std::vector<Derived> a(1);
foo(a);
}
You can also use std::transform with std::back_inserter, see [https://stackoverflow.com/a/33522799/638048]

Casting specialized base pointer to derived pointer that specializes on additional template parameter ("adding on" a specialization)

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

Downcasting instance of base class to derived class

I am interested if it is safe, to DOWNCAST (thanks Mike) an instance of a base class to a derived class under certain conditions. I think a sample is the most easy way to explain:
struct BaseA
{
void foo() const {}
double bar_member;
// no virtuals here
};
struct DerivedA : public BaseA
{
double bar(double z) {bar_member = z;return bar_member;}
// DerivedA does not add ANY member variables to BaseA.
// It also does not introduce ANY virtual functions.
};
struct BaseB
{
BaseA baseA;
};
// add extra functionality to B, to do this,
// i also need more functionality on baseA.
struct DerivedB : public BaseB
{
// is this "safe"? since BaseA and DerivedA
// should have the same memory layout?!?
DerivedA& getA() {return *static_cast<DerivedA*>(&baseA);}
double foo(double z) {return getA().bar(z);}
};
#include <iostream>
int main(int argc, char** argv)
{
DerivedB b;
// compiles and prints expected result
std::cout << b.foo(argc) << std::endl;
}
In my case, the classes BaseA and BaseB implement some kind of view concept. However, they also hold all the data members required to add further functionality in the derived classes. I know that I could implement the view to hold only a reference to the class providing the functionality. However, that would comes with some drawbacks:
I need to rewrite the whole interface for the view classes.
In my case, the Derived classes possesses an extra template argument (a callback type), which I want to have erased in the view. Hence, the view must not hold a direct reference to the classes providing functionality.
I tested my code, it works, however, I don't really trust the approach. And yes, I know I could achieve some of this with virtuals etc. but it is really performance critical...
Any ideas, hints, are welcome
Martin
for the interested people:
i changed my design the following way:
struct DerivedB : public BaseB
{
// encapsule the required extended functionality of BaseA member
struct OperateOnBaseA
{
OperateOnBaseA(BaseA& a);
double dosomething(double);
};
OperateOnBaseA a_extension;
DerivedB() :a_extension(baseA) {}
double foo(double z) {return a_extension.dosomething();}
};
As to the technical side: It is of course forbidden by the 2011 standard, 5.2.9.11, static cast. Let B be a base of D:
If the prvalue of type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.
On the other hand I'd be surprised if somebody could find an implementation which doesn't just do it, because of the obvious implementations of classes, methods and static casts.
Your existing code has undefined behaviour, as stated in the other answers. You can avoid that, if you don't mind some truly horrible code, by destroying the object at baseA and creating a DerivedA at the same location, so the downcast is valid:
#include <new>
struct DerivedB : public BaseB
{
DerivedB()
{
static_assert( sizeof(BaseA) == sizeof(DerivedA), "same size" );
baseA.~BaseA();
::new(&baseA) DerivedA();
}
~DerivedB()
{
getA().~DerivedA();
::new(&baseA) BaseA();
}
DerivedA& getA() {return *static_cast<DerivedA*>(&baseA);}
double foo(double z) {return getA().bar(z);}
};
The destructor restores an object of the original type, so that when the BaseB destructor destroys its baseA member it runs the destructor of the correct type on the object.
But I would avoid doing this and redesign your classes to solve it another way.
I don't find your approad clean enough for what you're trying to do. Assuming there's a "data source type" SourceA and a "data view type" ViewB, I would go more like this:
#include <iostream>
using namespace std;
template<typename T>
class SourceA_base
{
protected:
T data;
public:
using value_type = T;
SourceA_base(T&& a) : data(std::move(a)) { }
SourceA_base(T const& a) : data() { }
void foo() const {}
};
template<typename T>
class SourceA : public SourceA_base<T>
{
using B = SourceA_base<T>;
public:
using B::B;
T bar(T z) { return B::data = z; }
};
template<typename U>
class ViewB_base
{
protected:
U&& source;
public:
using value_type = typename std::remove_reference<U>::type::value_type;
ViewB_base(U&& a) : source(std::forward<U>(a)) { }
};
template<typename U>
class ViewB : public ViewB_base<U>
{
using B = ViewB_base<U>;
using T = typename B::value_type;
public:
using B::B;
T foo(T z) { return B::source.bar(z); }
};
int main ()
{
using S = SourceA<double>;
S a{3.14};
ViewB<S&> b{a};
std::cout << b.foo(6.28) << std::endl; // compiles and prints expected result
std::cout << ViewB<S>{S{2}}.foo(4) << std::endl; // still works
}
That is, all (source/view) types are templated, views contain references, and there are no downcasts. On your reservations for the use of references:
Re-writing the whole interface: No need now, thanks to templates.
Erasing callback types: First, type erasure and performance critical applications are not always good friends. Second, you'd better have the callback erase its own underlying type(s), not the view erase the type of the callback. Each class should do its own job. Or, don't erase types and make them template parameters.
I used rvalue-references so that the whole thing works for temporaries as well, as shown in my second example. Maybe constructors are not always complete/correct here. e.g. for const references; I reality would have fully templated constructors (accepting universal references), but to make this cooperate with one-argument implicitly defined copy/move constructors is a bit trickier (needs type traits and enable_if) and I only wanted to hightlight the idea here.
You may also consider using tuples to hold data, taking advantage of their empty base optimization.
As for your original question, this downcast is something I would never do; for the technical side, see Peter Schneider's answer.