Say I have
class Parent
{};
class ChildOne : Parent
{};
class ChildTwo : Parent
{};
void SomeMethod(std::vector<Parent*>& parents);
I understand why I can't pass a std::vector<ChildOne*> as an argument to SomeMethod as it's possible that SomeMethod may be:
void SomeMethod(std::vector<Parent*>& parents)
{
parents.push_back(new ChildTwo);
}
which would be invalid.
But why can't I pass a std::vector<ChildOne*> as an argument to
void AnotherMethod(const std::vector<Parent*>& parents);
In this case I can't think of what could go wrong, but I must be missing something.
EDIT:
To clarify, I'm wondering why this restriction exists. In C# (for example), this would compile (with IEnumerables). I assume that there is a failure case that exists.
You're right that it could work in this particular case and on most common platforms. However, it would be a terrible can of worms to allow this generally.
Consider that the standard doesn't guarantee all data pointers to be of the same size (for example, there are platforms where char* is larger than int*, because they don't have individually addressible bytes). The fact that you can convert a pointer-to-derived into a pointer-to-base does not mean that this conversion is trivial and does not affect the representation in memory. After all, as soon as multiple inheritance enters the picture, even this conversion start to involve changing the value of the pointer.
At the same time, templates are quite opaque in general. We know that a sane implementation of std::vector<T*> will use the same layout for its data for all Ts, as long as T* are the same size. But in general, a template can do anything based on its template arguments, with totally incompatible data layout.
Not to mention specialisation - if the template was specialised for <ChildOne*>, it could be totally incompatible.
Yes, there are cases where a const reference to a particular implementation of a template instantiated with Parent* could be aliased to the same template instantiated with ChildOne*. But these are extremely fragile, and in the general case such substitutability would allow innumerable bugs.
If you know that on your platform with your implementation of the standard library and with your types it's safe, you can create a casting function for it:
template <class D, class S>
const std::vector<D*>& base_cast(const std::vector<S*> &src)
{
return reinterpret_cast<const std::vector<D*>&>(src);
}
But use at your own risk.
std::vector<ChildOne*>
and
std::vector<Parent*>
are two different/"unrelated" types.
Years later, but I found a section of "The c++ Programming Language" that answers this question, section 27.2.1
"Logically, we count treat an immutable set<Circle*> as an immutable set because the problem of inserting an inappropriate element into the set cannot occur when we cannot change the set. That is, we could provide a conversion from const set<const Circle*> to const set<const Shape*>. The language doesn't do so by default, but the designer of set could."
Related
Often when writing templated code, I find myself needing to store an instance of the template type in a member variable. For example, I might need to cache a value to be used later on. I would like to be able to write my code as:
struct Foo
{
template<typename T>
T member;
template<typename T>
void setMember(T value)
{
member<T> = value;
}
template<typename T>
T getMember()
{
return member<T>;
}
};
Where members are specialized as they are used. My question:
Is such templated member variable possible with current C++ generative coding facilities?
If not, are there any proposals for such a language feature?
If not, are there any technical reasons why such a thing is not possible?
It should be obvious that I do not want to list all possible types (e.g. in a std::variant) as that is not generative programming and would not be possible if the user of the library is not the same as the author.
Edit: I think this somewhat answers my 3rd question from above. The reason being that today's compilers are not able to postpone instantiation of objects to after the whole program has been parsed:
https://stackoverflow.com/a/27709454/3847255
This is possible in the library by combining existing facilities.
The simplest implementation would be
std::unordered_map<std::type_index, std::any>
This is mildly inefficient since it stores each std::type_index object twice (once in the key and once inside each std::any), so a std::unordered_set<std::any> with custom transparent hash and comparator would be more efficient; this would be more work though.
Example.
As you say, the user of the library may not be the same as the author; in particular, the destructor of Foo does not know which types were set, but it must locate those objects and call their destructors, noting that the set of types used may be different between instances of Foo, so this information must be stored in a runtime container within Foo.
If you're wary about the RTTI overhead implied by std::type_index and std::any, we can replace them with lower-level equivalents. For std::type_index you can use a pointer to a static tag variable template instantiation (or any similar facility), and for std::any you can use a type-erased std::unique_ptr<void, void(*)(void*)> where the deleter is a function pointer:
using ErasedPtr = std::unique_ptr<void, void(*)(void*)>;
std::unordered_map<void*, ErasedPtr> member;
struct tag {};
template<class T> inline static tag type_tag;
member.insert_or_assign(&type_tag<T>, ErasedPtr{new T(value), [](void* p) {
delete static_cast<T*>(p);
}});
Example. Note that once you make the deleter of std::unique_ptr a function pointer, it is no longer default-constructible, so we can't use operator[] any more but must use insert_or_assign and find. (Again, we've got the same DRY violation / inefficiency, since the deleter could be used as the key into the map; exploiting this is left as an exercise for the reader.)
Is such templated member variable possible with current C++ generative coding facilities?
No, not exactly what you describe. What is possible is to make the enclosing class a template and use the template parameters to describe the types of the class' members.
template< typename T >
struct Foo
{
T member;
void setMember(T value)
{
member = value;
}
T getMember()
{
return member;
}
};
In C++14 and later, there are variable templates, but you can't make a template non-static data member of a class.
If not, are there any proposals for such a language feature?
Not that I know of.
If not, are there any technical reasons why such a thing is not possible?
The primary reason is that that would make it impossible to define binary representation of the class. As opposed to templates, a class is a type, which means its representation must be fixed, meaning that at any place in the program Foo and Foo::member must mean the same things - same types, same object sizes and binary layout, and so on. A template, on the other hand, is not a type (or, in case of variable templates, is not an object). It becomes one when it is instantiated, and each template instantiation is a separate type (in case of variable templates - object).
I am trying to implement a C++ class which will wrap a value (among other things). This value may be one of a number of types (string, memory buffer, number, vector).
The easy way to implement this would be to do something like this
class A {
Type type;
// Only one of these will be valid data; which one will be indicated by `type` (an enum)
std::wstring wData{};
long dwData{};
MemoryBuffer lpData{};
std::vector<std::wstring> vData{};
};
This feels inelegant and like it wastes memory.
I also tried implementing this as a union, but it came with significant development overhead (defining custom destructors/move constructors/copy constructors), and even with all of those, there were still some errors I encountered.
I've also considered making A a base class and making a derived class for each possible value it can hold. This also feels like it isn't a great way to solve the problem.
My last approach would be to make each member an std::optional, but this still adds some overhead.
Which approach would be the best? Or is there another design that works better than any of these?
Use std::variant. It is typesafe, tested and exactly the right thing for a finite number of possible types.
It also gets rid of the type enum.
class A {
std::variant<std::wstring, long, MemoryBuffer, std::vector<std::wstring>> m_data{}; // default initializes the wstring.
public
template<class T>
void set_data(T&& data) {
m_data = std::forward<T>(data);
}
int get_index() { // returns index of type.
m_data.index();
}
long& get_ldata() {
return std::get<long>(m_data); // throws if long is not the active type
}
// and the others, or
template<class T>
T& get_data() { // by type
return std::get<T>(m_data);
}
template<int N>
auto get_data() { // by index
return std::get<N>(m_data);
}
};
// using:
A a;
a.index() == 0; // true
a.set_data(42);
a.index() == 1; // true
auto l = a.get<long>(); // l is now of type long, has value 42
a.get<long>() = 1;
l = a.get<1>();
PS: This example does not even include the coolest (in my opinion) feature of std::variant: std::visit I am not sure what you want to do with your class, so I cannot create a meaningful example. If you let me know, I will think about it.
You basically want QVariant without the rest of Qt, then :)?
As others have mentioned, you could use std::variant and put using MyVariant = std::variant<t1, t2, ...> in some common header, and then use it everywhere it's called for. This isn't as inelegant as you may think - the specific types to be passed around are only provided in one place. It is the only way to do it without building a metatype machinery that can encapsulate operations on any type of an object.
That's where boost::any comes in: it does precisely that. It wraps concepts, and thus supports any object that implements these concepts. What concepts are required depends on you, but in general you'd want to choose enough of them to make the type usable and useful, yet not too many so as to exclude some types prematurely. It's probably the way to go, you'd have: using MyVariant = any<construct, _a>; then (where construct is a contract list, an example of which is as an example in the documentation, and _a is a type placeholder from boost::type_erasure.
The fundamental difference between std::variant and boost::any is that variant is parametrized on concrete types, whereas any is parametrized on contracts that the types are bound to. Then, any will happily store an arbitrary type that fulfills all of those contracts. The "central location" where you define an alias for the variant type will constantly grow with variant, as you need to encapsulate more type. With any, the central location will be mostly static, and would change rarely, since changing the contract requirements is likely to require fixes/adaptations to the carried types as well as points of use.
I went through some searches but couldn't quite find this one. Consider this situation:
template <class T> class TemplClass;
void a_function(TemplClass<const X>&);
TemplClass<X> inst;
a_function( inst ); // fails
"invalid initialization of reference of type ‘TemplClass&’ from expression of type ‘TemplClass’"
The situation is 100% safe as far as I can tell. Still, C++ does not allow this. So I wonder what cast to use instead of the trivial C-cast.
a_function( static_cast<TemplClass<const X>&>(inst) ); // fails, similar error message
a_function( reinterpret_cast<TemplClass<const X>&>(inst) ); // works
dynamic_cast is out of the question, const_cast fails too (and rightly so).
The reinterpret_cast feels fishy (is it though?). But is there a solution with some kind of trick that I missed? Anyone know why the standard does not simply detect that this is something good? Or is there something 'bad' about this cast?
TemplClass<const T> and TemplClass<T> are unrelated types.
For example you may have (partial) specialization to make them really different:
template<typename T>
class TemplClass
{
void generic();
std::string s;
};
template<typename T>
class TemplClass<const T>
{
void foo();
std::vector<int> v;
};
Casting one into the other doesn't make sense.
In the same way
class A
{
char* p;
};
class B
{
char* p;
};
Those 2 classes are unrelated (even if it seems identical).
But is there a solution with some kind of trick that I missed?
The ideal solution is to not write such restricted template interfaces. For example, consider the standard library algorithms that take iterators to represent ranges rather than specific template types with specific object types.
If you're unable to fix the interface as it's say in a third party library, then you're going to be stuck copying your Templ<X> to a Templ<const X> before making the call.
Anyone know why the standard does not simply detect that this is
something good?
Because it's not good. The very simplest case is where there are template specializations where it would change some meaning/functionality. The compiler can't simply change the instantiation of the template.
Or is there something 'bad' about this cast?
By the language, the cast is illegal because the const and non-const template instantiations are unrelated types. Depending on the actual case, there are probably legal alternatives.
Situation
I have a template class TIppImage<T> for image of type T. I have singleton class CIppMemoryManager which can store a number of images of different size and type.
class CIppMemoryManager
{
public:
/// ... Singleton interface ...
template<class T> TIppImage<T>* GetImage(width, height);
private:
CIppMemoryManager();
~CIppMemoryManager();
std::map<IppDataType, void*> m_Containers;
};
IppDataType is enum, which values correspond to actual types. All management is done in template class TIppImageContainer<T>. And all specialization of this class is stored in m_Containers as a void*. It's not very good, but it is at least simple.
With this approach, I can simply implement template GetImage method like this:
template<class T> TIppImage<T>* CIppMemoryManager::GetImage(width, height)
{
return reinterpret_cast<TIppImageContainer<T>*>(m_Containers[
TIppTypeTraits<T>::ipp_data_type])->GetImage(width, height);
}
where I'm using traits class TIppTypeTraits<T> to obtain enum value from given type.
Problem
I cannot simply implement non-template methods like constructor. I need to explicitly handle all possible types:
CIppMemoryManager::CIppMemoryManager()
{
m_Containers[ipp8u] = new CIppImageContainer<Ipp8u>;
m_Containers[ipp8s] = new CIppImageContainer<Ipp8s>;
m_Containers[ipp16u] = new CIppImageContainer<Ipp16u>;
m_Containers[ipp16s] = new CIppImageContainer<Ipp16s>;
...
}
Worse, for destructor I also need to deal with void*:
CIppMemoryManager::~CIppMemoryManager()
{
delete reinterpret_cast<TIppImageContainer<Ipp8u>*>(m_Containers[ipp8u]);
delete reinterpret_cast<TIppImageContainer<Ipp8s>*>(m_Containers[ipp8s]);
delete reinterpret_cast<TIppImageContainer<Ipp16u>*>(m_Containers[ipp16u]);
delete reinterpret_cast<TIppImageContainer<Ipp16s>*>(m_Containers[ipp16s]);
...
}
So, the questions are:
a) Is there some way to iterate through collection of different types? Cannot use traits class here since function is non-template.
b) Is there some better way to store collection of containers - objects of different type? When they are just a different specialization of common template class, containers itself are pretty simple.
I think the class variant from the boost library (boost::variant) may help you. You can use visitors to execute the appropriate code depending on the type stored in a variant. A std::vector<boost::variant<T0, T1,...>> can store a list of objects of different types.
As your objects are similar, they may have the same size in memory, which is a good thing since boost::variant storage is stack-based (no heap allocation - this is faster).
What's wrong with polymorphic CIppImageContainer<T> (make them all share a common base class) and a smart pointer ?
Or some kind of boost::variant ?
boost::mpl::for_each is tailor-made for that job. Define a vector of types to operate on, a functor or lambda expression to do something, and you are done.
boost::variant is the most likely candidate but sometimes variantS become rather large as they require some extra storage and also have to deal with alignment. So maybe boost::any has advantages in some situations as well:
std::vector<std::pair< Type, boost::any > > data;
To comfortably iterate over such a container is harder (boost::transform_iterator cannot have more than one return type, so this wont work without some template trickery).
I often have classes that are mostly just wrappers around some STL container, like this:
class Foo {
public:
typedef std::vector<whatever> Vec;
typedef Vec::size_type size_type;
const Vec& GetVec() { return vec_; }
size_type size() { return vec_.size() }
private:
Vec vec_;
};
I am not so sure about returning size_type. Often, some function will call size() and pass that value on to another function and that one will use it and maybe pass it on. Now everyone has to include that Foo header, although I'm really just passing some size value around, which should just be unsigned int anyway ...? What is the right thing to do here? Is it best practice to really use size_type everywhere?
It should be vector<>::size_type like you have, this is the most correct way.
That said, I know many people, including myself, will just use size_t instead. Although it's not mandated to be the same, vector<>::size_type is size_t for every implementation I know. You should be fine with that.
STL defines these types as an abstract interface for containers. It is intended to support any type of backing storage. That might be NUMA or disk-backed storage, where size_type and ptr-type are different from those for system memory. Or - in a NUMA architecture - it might be a specific memory node that's fast, and can work with a very small size_type and ptr_type - which is a relevant optimization on many architectures.
At least, that were the design goals, also driven by anticipation what could be platforms supporting C++. Some early concessions also allowed shortcuts for STL implementers that basically disable this flexibility, and I've never worked with an STL implementation that made use of this. I'd say that's because linear memory access has become much less of a problem, and STL development at that level isn't actually easy.
Still, how much does it hurt you? It would be the right thing to do.
Actually, it should be size_t and not unsigned int, for 64-bit compatibility. As wrapper class writer, I would return size_type. As class client, I would cast it to appropriate type (size_t), if it is more convenient.
I am not so sure about returning
size_type. Often, some function will
call size() and pass that value on to
another function and that one will use
it and maybe pass it on. Now everyone
has to include that Foo header...
It's fine to return the size_type, but this doesn't mean another function should necessarily take the same size_type as typedeffed in your class. There exist conversions between integral types. Be brave and just use size_t.
You can't overload functions anyway so that there would be one that works with size of vector, another for size of deque etc, just in case they all happen to be using a different size_type (which the standard probably permits). - But you could also use templates, if possible, to deduce the correct size_type to use from the argument.
One option you could consider is inheriting from std::vector :
typedef std::vector<whatever> Foo_Vec;
class Foo : public Foo_Vec
{
public:
const Foo_Vec &GetVec() { return (Foo_Vec&)*this; }
};
I am by no means saying this is the best approach, as it can introduce issues that wouldn't occur by having a private member or inheriting from private Foo_Vec, as public Foo_Vec exposes all methods on std::vector to Foo. Moreover, std::vector does not have a virtual destructor, so if you attempt to clean up a collection of std::vector's with a Foo tucked in there, it won't get cleaned up entirely. I'm just throwing it out there.
As other answers suggest, you should use size_t or size_type instead of unsigned int for 64-bit compatibility. Otherwise, in a future 64-bit build, your std::vector could have more than 232 items, but the size value would be truncated, leading to bugs.