I am wondering if it is possible to convert a vector of derived class values to a vector of base class values. Specifically I want to be able to pass a vector of base class objects to a function whose formal parameters takes a vector of base class. It does not appear to be possible directly as the following code example produces an error (using g++):
#include <vector>
class A {
};
class B : public A {
};
void function(std::vector<A> objs) {
}
int main(int argc, char **argv) {
std::vector<B> objs_b;
objs_b.push_back(B());
function(objs_b);
}
test.cc:16: error: conversion from ‘std::vector<B, std::allocator<B> >’ to non-scalar type ‘std::vector<A, std::allocator<A> >’ requested
I would like to be able to be able to call function without having to define a new vector with elements of type A, inserting my elements of type B or changing to a vector of pointers.
No, it is not. vector<B> is not derived from vector<A>, regardless of the fact that B is derived from A. You will have to change your function somehow.
A more idiomatically C++ approach might be to template it and have it take a pair of iterators - this is why the various standard library functions (<algorithm> etc) work that way, because it separates the implementation of the algorithm from the kind of thing it's operating on.
Sometimes there are ways around this. Take a loot at Boost and some of the template meta-programming packages they have or use. Specifically I'd look at is_base_of for these kinds of purposes combined with partial template specialization.
For instance, if you wish to do some template magic trickery:
template<typename T, bool Allowed>
struct TemplateVectorCode;
You make a forward declaration of a templated class. Then you make a specialization with a "true" boolean value:
template<typename T> struct TemplateVectorCode<T, true>{
void operator(const std::vector<T>& myVector) const{ //definition in here }
};
Finally you use that with is_base_of to only instantiate instances of your template functor in the following manner:
template<typename T, typename Base>
struct MyFunction : TemplateVectorCode<T, boost::is_base_of<Base,T>::value>{
};
The important point to note is that since we have not defined a TemplateVectorCode<T, false> the compiler will throw a compile error if you attempt to use your functor with a class type T that does not derive from the type V. That means you can work with the same code in one place without having to write multiple versions of it.
(if I screwed up the partial template specialization, someone please edit it. I need to go to bed.)
Here is how to make your function accept standard vectors of any child classes of a given type (in this case, class A) using templates in C++14.
class A {};
class B : public A {};
template<typename T, std::enable_if_t<std::is_base_of_v<A, T>, bool> = true>
void function(const std::vector<T>& vec) {
// implemenation
}
std::vector<A> vec_a;
std::vector<B> vec_b;
function(vec_a); // ok
function(vec_b); // ok
Related
I have a recursive data type like this:
template<typename T>
struct SomeType {
std::map<T, SomeType<T>> mapping;
};
SomeType<int> foo;
This works fine, but replacing std::map with std::unordered_map results in a compile error due to an incomplete type. Am I (or gcc) making an error somewhere? or is this just part of the standard?
I would also like to have the internal container determined by a template parameter (like std::stack and std::queue), but I can't figure out a way to do it since that would require SomeType to already be defined.
Incomplete example:
template<typename T, typename C = std::map<T, SomeType<[???]>>>
struct SomeType {
C mapping;
};
SomeType<int, [???]> foo;
I know this can be done with runtime indirection, but that's not what I'm looking for.
Your class is incomplete anywhere before the final } of its definition. So the mapping member is using incomplete type SomeType in its type's template arguments.
The standard does not allow this, and it is pure luck that it works with some STL containers.
Your second questions falls under the same answer -- it is illegal to do that in the first place.
You cannot define a template with recursive default parameters for obvious reasons. You also cannot instantiate standard library container templates on incomplete types, because the standard says so (otherwise it's undefined behaviour). The usual PIMPL idiom may help, though:
#include <map>
#include <memory>
template <typename T> class SomeType
{
typedef std::map<T, SomeType<T>> map_type;
typedef std::unique_ptr<map_type> map_ptr;
map_ptr pimpl;
public:
SomeType() : pimpl(new map_type) { }
};
While you cannot use incomplete types with containers, you can do it with smart pointers.
And while you cannot create template types with undefined types parameters, you can use some tricks here:
template<typename T, template <typename U, typename V, typename... Args> class Container = std::unordered_map >
struct SomeType {
Container<T, std::unique_ptr<SomeType> > mapping;
};
How do I declare a templated type that refers to itself?
template <class T = Animal> class Animal
{
public:
T getChild ();
}
With this, I get a compiler error concerning a missing type specifier. I tried to forward-declare Animal, without success.
I am trying to impose a type constraint. A Lion can only have a Lion as a child, a Bear has a Bear, and so on.
EDIT
I'll post part of the actual class. It is a template for classes that can appear in a linked list:
template <class T = Linked<T> > class Linked
{
private:
T* m_prev;
T* m_next;
}
I want to enforce that the class can only point to object of the same class (or a subclass).
In this case, you need to specify some type parameter to Animal in your typename definition, or else it would be an "infinite recursion" in the type construction:
template<class T> class Animal;//you'll need this forward declaration
template <class T = Animal<int> > class Animal //int is just an example
{
public:
T getPrey ();
}
The OP has been answered but I want to chime in because the immediate cause of the problem is not recursion, as others claim. The simplest reason this wouldn't work is that class templates are not types. They are templates. Similarly, function templates are not functions either. So all of this is nonsensical:
template<typename T> int function_template(int);
typedef int function_type(int);
void eats_a_function(function_type&); // needs a reference to function
std::vector< std::vector > vec0; // std::vector is not a type
std::vector< std::list > vec1; // std::list is not a type
eats_a_function(function_template); // function_template is not a function
Notice that in the vec1 case, std::list is not related to std::vector. The template is fully defined (assuming header inclusion) at the point of instantiation. It still won't work.
Instead, the following works:
std::vector< std::vector<int> > vec2; // std::vector<int> is a type
std::vector< std::list<double> > vec3; // std::list<double> is a type
eats_a_function(function_template<long>); // function_template<long> is a function
Notice that in the vec2 case, it's fine to pass an instantiation of the template itself.
For the record, a toy solution to the toy problem on writing a template that refers to itself, using the proverbial layer of indirection:
// expects a template that expects a type
template<template<class> class T> struct indirection {};
// forward decl. for defaulting the parameter
template<typename T> struct recursive;
// template that expects a type
template<typename T = indirection<recursive> > struct recursive {};
Not terribly powerful given the few things that are possible with a template (the T parameter inside indirection). It's of course possible to write a rebind-style metafunction that returns an instantiation of T.
The usual way to do something like a linked list is:
template <class T> class Linked
{
private:
Linked<T>* m_prev;
Linked<T>* m_next;
}
Does this work for you, and if not, what are you trying to accomplish that can't be done this way?
You can't create a template class wherein the template type is the class itself. This is a logical recursion that your compiler can't mitigate. Since templates require the compiler to construct the object when a specific typing is encountered ( say Animal ), you have to have a complete definition of the template type. Otherwise, the compiler will recursively try to construct objects. Since your object self-references, this will be an non-terminating recursion.
This use-case seems much more appropriate for inheritance than for templates.
Doing this will let you compile:
template class Animal
{
public:
T getPrey ();
}
Or, if you really wan't a default argument:
template <class T=Cheetah> class Animal
{
public:
T getPrey ();
}
Yet, cheetah must not use itself or Animal as one of its potential template types.
In this piece I'm trying to declare in Class B a list that can hold objects of Class A of any type, such as A<int>, A<double>, A<float>. I intend to add A objects to the list during runtime:
#include <list>
template <class T> class A {};
class B {
template<class T> std::list<A<T>*> objects;
};
It seems like making a list like this should work but compiling it gives an error:
Line 6: error: data member 'objects' cannot be a member template
compilation terminated due to -Wfatal-errors.
Can somebody explain why this doesn't work and how I can fix it?
That's just not how C++ works. If you want to group different objects together, they need to have at least some relation. Being instantiations of the same class template doesn't imply that they are related, they're completely distinct types. If you want a list of A<T>*s, better make a list of base-class pointers and forward operations through virtual functions:
class A_base{
public:
virtual void foo() = 0;
virtual ~A_base() { }
};
template<class T>
class A : public A_base{
public:
void foo(){
// ...
}
};
class B{
std::list<A_base*> objects;
};
Member variables aren't allowed to be templates. Only member functions can be templates. You'll have to templatize the enclosing class B instead:
template <class T>
class B {
std::list<A<T>*> objects;
};
Unfortunately you cannot have template variables. Only option to declare a member data is to make the class template:
template<class T>
class B {
std::list<A<T>*> objects;
};
Depending on what you're doing, type erasure might be an option. On the Tension Between Object-Oriented and Generic Programming in C++ is my favorite write-up on the subject.
In a nutshell, you convert the static dispatch enabled by the templates into dynamic dispatch through a custom inheritance tree you setup on the fly. Instead of storing A<T>, you create a new type that has the common interface you desire, and using some template/inhertiance voodoo this new type stores an A<T> without actually exposing the T. So A<int> and A<double> and A<A<std::list<A<int> > > > and some_type_that_looks_like_A_but_really_isnt all reduce down to a single type.
But you have to have a common interface, independant of that parameter. If you can't, things get more difficult.
Boost.Any is a good example, as is std::shared_ptr [which uses type erasure to remember how to delete the pointer passed to it even in the face of non-polymorphic inheritance].
Make B class template just like you've made A a class template:
template<class T>
class B {
std::list<A<T>*> objects;
};
I am wondering if it is possible to convert a vector of derived class values to a vector of base class values. Specifically I want to be able to pass a vector of base class objects to a function whose formal parameters takes a vector of base class. It does not appear to be possible directly as the following code example produces an error (using g++):
#include <vector>
class A {
};
class B : public A {
};
void function(std::vector<A> objs) {
}
int main(int argc, char **argv) {
std::vector<B> objs_b;
objs_b.push_back(B());
function(objs_b);
}
test.cc:16: error: conversion from ‘std::vector<B, std::allocator<B> >’ to non-scalar type ‘std::vector<A, std::allocator<A> >’ requested
I would like to be able to be able to call function without having to define a new vector with elements of type A, inserting my elements of type B or changing to a vector of pointers.
No, it is not. vector<B> is not derived from vector<A>, regardless of the fact that B is derived from A. You will have to change your function somehow.
A more idiomatically C++ approach might be to template it and have it take a pair of iterators - this is why the various standard library functions (<algorithm> etc) work that way, because it separates the implementation of the algorithm from the kind of thing it's operating on.
Sometimes there are ways around this. Take a loot at Boost and some of the template meta-programming packages they have or use. Specifically I'd look at is_base_of for these kinds of purposes combined with partial template specialization.
For instance, if you wish to do some template magic trickery:
template<typename T, bool Allowed>
struct TemplateVectorCode;
You make a forward declaration of a templated class. Then you make a specialization with a "true" boolean value:
template<typename T> struct TemplateVectorCode<T, true>{
void operator(const std::vector<T>& myVector) const{ //definition in here }
};
Finally you use that with is_base_of to only instantiate instances of your template functor in the following manner:
template<typename T, typename Base>
struct MyFunction : TemplateVectorCode<T, boost::is_base_of<Base,T>::value>{
};
The important point to note is that since we have not defined a TemplateVectorCode<T, false> the compiler will throw a compile error if you attempt to use your functor with a class type T that does not derive from the type V. That means you can work with the same code in one place without having to write multiple versions of it.
(if I screwed up the partial template specialization, someone please edit it. I need to go to bed.)
Here is how to make your function accept standard vectors of any child classes of a given type (in this case, class A) using templates in C++14.
class A {};
class B : public A {};
template<typename T, std::enable_if_t<std::is_base_of_v<A, T>, bool> = true>
void function(const std::vector<T>& vec) {
// implemenation
}
std::vector<A> vec_a;
std::vector<B> vec_b;
function(vec_a); // ok
function(vec_b); // ok
I'm trying to use decltype in the late specified return of a member function in a CRTP base class and it's erroring with: invalid use of incomplete type const struct AnyOp<main()::<lambda(int)> >.
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<const Op*>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
template<class Functor>
struct AnyOp : Operation<AnyOp<Functor> >
{
explicit AnyOp(Functor func) : func_(func) {}
template<class Foo>
bool call_with_foo(const Foo &foo) const
{
//do whatever
}
private:
Functor func_;
};
I'm basically trying to move all of the sfinae boiler plate into a base class so I don't need to repeat it for every Operation that I create (currently each operation has 6 different calls and there are ~50 operations so there is quite a lot of repetition with the enable_if's).
I've tried a solution which relied on overloading but one of the types which may be passed is anything that's callable(this can be a regular functor from C++03 or a C++0x lambda) which I bound to a std::function, unfortunately, the overhead from std::function, although very minimal, actually makes a difference in this application.
Is there a way to fix what I currently have or is there a better solution all together to solve this problem?
Thanks.
You are, as another answer describes already, trying to access a member of a class in one of the class' base class. That's going to fail because the member is yet undeclared at that point.
When it instantiates the base class, it instantiates all its member declarations, so it needs to know the return type. You can make the return type be dependent on Foo, which makes it delay the computation of the return type until Foo is known. This would change the base class like the following
// ignore<T, U> == identity<T>
template<typename T, typename Ignore>
struct ignore { typedef T type; };
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<typename ignore<const Op*, Foo>::type>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
This artificially makes the static_cast cast to a type dependent on Foo, so it does not immediately require a complete Op type. Rather, the type needs to be complete when operator() is instantiated with the respective template argument.
You are trying to refer to a member of a class from one of its own base classes, which will fail since the class's body doesn't exist within its base class. Can you pass the logic for computing the return type of call_with_foo as a metafunction to the base class? Is that logic ever going to be complicated?
Another option, depending on how much flexibility you have in changing your class hierarchy (and remember that you have template typedefs), is to have the wrapper inherit from the implementation class rather than the other way around. For example, you can write a AddParensWrapper<T> that inherits from T and has operator() that forwards to T::call_with_foo. That will fix the dependency problem.