I'm trying to deal with circular dependency in following scenario:
I've got a std::variant, say:
//types.h
using Types = std::variant<int, double, std::string, SomeClass>;
SomeClass is a pretty simple thing holding few pointers, with some template logic:
#someclass.h
class SomeClass {
// few simple members (pointers and an integer)
void use(Types arg); // note usage of Types here
template<typename T, typename Ts...> // implicitly assuming T == Ts... == Types
void use(T arg, Ts... tail) {
use(arg);
use(tail...);
}
SomeClass(const SomeClass&) = default; // works fine
};
Usually I would forward-declare SomeClass before "using Types...", but it can't be done when it comes to std::variant. I also didn't really found a way to forward-declare the "using" directive.
One way I found was forward-declaring SomeClass and using a pointer to it in Types, but I don't like this idea (SomeClass is a really light object with short lifespan, I'd want to keep it out of heap).
Is there any other way (beside pointers) in C++ to solve this one? I'm running out of ideas.
Thanks :)
EDIT:
The issue actually appears only if I'm trying to use Types before really defining SomeClass, see https://godbolt.org/z/4jzhEd
In the live example you provided, all you need to solve the issue is define SomeStruct after SomeClass.
This way your Types variant will no longer have any incomplete types when SomeStruct is defined. In other words, here is the order:
class SomeClass;
using Types = std::variant<..., SomeClass>;
class SomeClass {
// ... // Types used here, but doesn't need to have all complete types
};
struct SomeStruct {
Types value;
// ...
};
See here for a live example.
Related
There is a templated class, let it be
template<typename T> class A { std::vector<T> data; };
The problem I am facing here is, users can create several types of this class, but I need to track them, best case is I have a reference of these objects in another vector, but that would not work since all types are different.
Can you recommend a good design pattern which can encapsulate this.
I can store pointers and then typecast it, but its not elegant.
I can change the architecture as well, if the solution provided is good enough.
The basic question I am trying to solve is, I have a class of vector of custom types, how do I store them.
As previous comments stated - you first need to make sure this is what you need.
With that been said, I had a similar requirement in a project of mine, which I eventually solved with inheritance and PIMPL, as follows:
class A{
private:
struct Abstract {
virtual void f() = 0;
};
template <typename T>
struct Implementation : public Abstract {
std::vector<T> data;
virtual void f() {...}
};
std::unique_ptr<Abstract> impl;
public:
template <typename T>
A(): impl(std::make_unique<Implementation<T> >()){}
void f() {impl->f();}
};
This allows you to create a container of objects of type A, and access them via the public interface defined therein (the method f). The underlying type T of each A object is specified on construction. All other implementation details specific to the type T are hidden.
The solution suffers the inherent overhead of virtual functions. I'm not sure how it compares to the std::any approach performance-wise.
std::any is the modern c++17 solution. Specifically, you should use
A<int> a;
a.data.push_back(0);
// fill refernces...
std::vector<std::any> refernces;
refernces.push_back(&a.data[0]);
// check which type is active.
if(int** iPtr = std::any_cast<int*>(&references[0]); iPtr != nullptr)
{
// its an int*
int& i = **iPtr;
// do something with i.
}
These pointers can point into the A<int>::data and A<double>::data vectors.
For a complete reference, see here https://en.cppreference.com/w/cpp/utility/any.
Apologies for the long question, but some context is necessary. I have a bit of code that seems to be a useful pattern for the project I'm working on:
class Foo
{
public:
Foo( int bar = 1 );
~Foo();
typedef std::shared_ptr< Foo > pointer_type;
static pointer_type make( int bar = 1 )
{
return std::make_shared< Foo >( bar );
}
...
}
As you can see, it provides a straightforward way of constructing any class as a PointerType which encapsulates a shared_ptr to that type:
auto oneFoo = Foo::make( 2 );
And therefore you get the advantages of shared_ptr without putting references to make_shared and shared_ptr all over the code base.
Encapsulating the smart pointer type within the class provides several advantages:
It lets you control the copyability and moveability of the pointer types.
It hides the shared_ptr details from callers, so that non-trivial object constructions, such as those that throw exceptions, can be placed within the Instance() call.
You can change the underlying smart pointer type when you're working with projects that use multiple smart pointer implementations. You could switch to a unique_ptr or even to raw pointers for a particular class, and calling code would remain the same.
It concentrates the details about (smart) pointer construction and aliasing within the class that knows most about how to do it.
It lets you decide which classes can use smart pointers and which classes must be constructed on the stack. The existence of the PointerType field provides a hint to callers about what types of pointers can be created that correspond for the class. If there is no PointerType defined for a class, this would indicate that no pointers to that class may be created; therefore that particular class must be created on the stack, RAII style.
However, I see no obvious way of applying this bit of code to all the classes in my project without typing the requisite typedef and static PointerType Instance() functions directly. I suspect there should be some consistent, C++11 standard, cross-platform way of doing this with policy-based templates, but a bit of experimentation has not turned up an obvious way of applying this trivially to a bunch of classes in a way that compiles cleanly on all modern C++ compilers.
Can you think of an elegant way to add these concepts to a bunch of classes, without a great deal of cutting and pasting? An ideal solution would conceptually limit what types of pointers can be created for which types of classes (one class uses shared_ptr and another uses raw pointers), and it would also handle instancing of any supported type by its own preferred method. Such a solution might even handle and/or limit coercion, by failing appropriately at compile time, between non-standard and standard smart and dumb pointer types.
One way is to use the curiously recurring template pattern.
template<typename T>
struct shared_factory
{
using pointer_type = std::shared_ptr<T>;
template<typename... Args>
static pointer_type make(Args&&... args)
{
return std::make_shared<T>(std::forward<Args>(args)...);
}
};
struct foo : public shared_factory<foo>
{
foo(char const*, int) {}
};
I believe this gives you what you want.
foo::pointer_type f = foo::make("hello, world", 42);
However...
I wouldn't recommend using this approach. Attempting to dictate how users of a type instantiate the type is unnecessarily restrictive. If they need a std::shared_ptr, they can create one. If they need a std::unique_ptr, they can create one. If they want to create an object on the stack, they can. I see nothing to be gained by mandating how your users' objects are created and managed.
To address your points:
It lets you control the copyability and moveability of the pointer types.
Of what benefit is this?
It hides the shared_ptr details from callers, so that non-trivial object constructions, such as those that throw exceptions, can be placed within the Instance() call.
I'm not sure what you mean here. Hopefully not that you can catch the exception and return a nullptr. That would be Java-grade bad.
You can change the underlying smart pointer type when you're working with projects that use multiple smart pointer implementations. You could switch to a unique_ptr or even to raw pointers for a particular class, and calling code would remain the same.
If you are working with multiple kinds of smart pointer, perhaps it would be better to let the user choose the appropriate kind for a given situation. Besides, I'd argue that having the same calling code but returning different kinds of handle is potentially confusing.
It concentrates the details about (smart) pointer construction and aliasing within the class that knows most about how to do it.
In what sense does a class know "most" about how to do pointer construction and aliasing?
It lets you decide which classes can use smart pointers and which classes must be constructed on the stack. The existence of the PointerType field provides a hint to callers about what types of pointers can be created that correspond for the class. If there is no PointerType defined for a class, this would indicate that no pointers to that class may be created; therefore that particular class must be created on the stack, RAII style.
Again, I disagree fundamentally with the idea that objects of a certain type must be created and managed in a certain way. This is one of the reasons why the singleton pattern is so insidious.
I wouldn't advise adding those static functions. Among other drawbacks, they really get pretty burdensome to create and maintain when there are multiple constructors. This is a case where auto can help as well as a typedef outside the class. Plus, you can use the std namespace (but please not in the header):
class Foo
{
public:
Foo();
~Foo();
Foo( int bar = 1 );
...
}
typedef std::shared_ptr<Foo> FooPtr;
In the C++ file:
using namespace std;
auto oneFoo = make_shared<Foo>( 2 );
FooPtr anotherFoo = make_shared<Foo>( 2 );
I think you'll find this to not be too burdensome on typing. Of course, this is all a matter of style.
This is a refinement of Joseph's answer for the sake of making the kind of pointer more configurable:
#include <memory>
template <typename T, template <typename...> class PtrT = std::shared_ptr>
struct ptr_factory {
using pointer_type = PtrT<T>;
template <typename... Args>
static pointer_type make(Args&&... args) {
return pointer_type{new T{args...}};
}
};
template <typename T>
struct ptr_factory<T, std::shared_ptr> {
using pointer_type = std::shared_ptr<T>;
template <typename... Args>
static pointer_type make(Args&&... args) {
return std::make_shared<T>(args...);
}
};
struct foo : public ptr_factory<foo> {
foo(char const*, int) {}
};
struct bar : public ptr_factory<bar, std::unique_ptr> {
bar(char const*, int) {}
};
ptr_factory defaults to using std::shared_ptr, but can be configured to use different smart pointer templates, thanks to template template parameters, as illustrated by struct bar.
Simple question: How do I get this to work?
struct A {
double whatever;
std::unordered_map<std::string, A> mapToMoreA;
}
g++ error: std::pair<_T1, _T2>::second has incomplete type
As far as I understand, when instantiating the map, the compiler needs to know the size of A, but it doesn't know this because the map is declared in A's declaration, so is the only way to get around this to use pointers to A (don't feel like doing that)?
Most of the time it will depend on the container implementation details (more precisely, on what gets instantiated at the point of container declaration and what doesn't). Apparently, std::unordered_map implementation requires the types to be complete. At the same time GCC's implementation of std::map compiles perfectly fine with incomplete type.
To illustrate the source of such difference, consider the following example. Let's say we decided to make our own naive implementation of std::vector-like functionality and declared our vector class as follows
template <typename T> class my_vector {
T *begin;
T *end;
...
};
As long as our class definition contains only pointers to T, the type T is not required to be complete for the class definition itself. We can instantiate my_vector itself for an incomplete T without any problems
class X;
my_vector<X> v; // OK
The "completeness" of the type would be required later, when we begin to use (and therefore instantiate) the individual methods of my_vector.
However, if for some reason we decide to include a direct instance of T into our vector class, things will chahge
template <typename T>
class my_vector {
T *begin;
T *end;
T dummy_element;
...
};
Now the completeness of T will be required very early, at the point of instantiation of my_vector itself
class X;
my_vector<X> v; // ERROR, incomplete type
Something like that must be happening in your case. The definition of unordered_map you are dealing with somehow contains a direct instance of A. Which is the reason why it is impossible to instantiate (obviously, you would end up with infinitely recursive type in that case).
A better thought through implementation of unordered_map would make sure not to include A into itself as a direct member. Such implementation would not require A to be complete. As you noted yourself, Boost's implementation of unordered_map is designed better in this regard.
I don't know of any STL containers other than smart pointers that work with incomplete types. You can use a wrapper struct however if you don't want to use pointers:
struct A {
struct B { double whatever; };
std::unordered_map<std::string, B> mapToB;
};
Edit: Here is a pointer alternative if the above doesn't meet your use case.
struct A {
double whatever;
std::unordered_map<std::string, std::unique_ptr<A>> mapToMoreA;
};
You can also just use boost::unordered_map which not only supports incomplete types but also has far greater debug performance in Visual Studio as Microsoft's implementation of std::unordered_map is incredibly inefficient due to excessive iterator debugging checks. I am unaware of any performance concerns on gcc for either container.
Boost.Variant has a handy utility explicitly for this purpose – boost::recusive_wrapper<>. The following should work:
struct A {
double whatever;
std::unordered_map<std::string, boost::recursive_wrapper<A>> mapToMoreA;
};
The only notable drawback is that Boost.Variant has not yet been updated to support C++11 move semantics. Update: added in Boost 1.56.
If having the map hold pointers isn't acceptable, perhaps this will work for you:
struct A {
struct hidden;
std::unique_ptr<hidden> pimpl;
};
struct A::hidden {
double whatever;
std::unordered_map<std::string, A> mapToMoreA;
};
In C++ you usually use pointers, which have predefined constant size, for incomplete types:
This of course changes how you use the map: you'll have to dereference with the * or -> operators to access members and have to delete the pointers at some point.
struct A
{
double bla;
std::map<std::string, A*> mapToMoreA;
};
Member functions of A should be split into a prototype inside the struct block and implemented later, otherwise A and its members are not yet completely defined:
struct A
{
double bla;
std::map<std::string, A*> mapToMoreA;
void doStuff(const std::string& str);
};
void A::doStuff(const std::string& str)
{
mapToMoreA[str] = new A();
}
Or use a pointer to the map. The pointer must be of type void* in this case (can be hidden behind a set of functions). Maybe there are alternatives to std::unordered_map that can cope with incomplete value types.
I think you can just forward declare struct A; prior to its definition and the compiler should be happy.
EDIT: So after being downvoted several times, I wrote the following to see what I was missing:
#include <boost/unordered_map.hpp>
#include <string>
#include <iostream>
struct A;
struct A {
double whatever;
boost::unordered_map<std::string, A> mapToMoreA;
};
int main(void)
{
A b;
b.whatever = 2.5;
b.mapToMoreA["abc"] = b;
std::cerr << b.mapToMoreA["abc"].whatever << std::endl;
return 0;
}
This compiles fine using g++ 4.2.1 on my mac, and prints out "2.5" when it's run (as expected).
Sorry that I don't have unordered_map without boost. Is that the issue? (i.e., does std::unordered_map somehow place more constraints on the compiler than boost does?) Otherwise, I'm not sure what I'm missing here about the question. Those downvoting this, please enlighten me with comments. Thanks!
Initially I was trying to typedef a template class and I got to the "gotw 79" article.
And I didn't want to create another class so I ended up doing the following. Basically typedef'ing inside the same class. It works obviously. but is it a good practice?
template <typename T,typename L>
class MyClass{
typedef std::tr1::shared_ptr<MyClass<T,L> > shrdPtr;
}
Thank you.
Well, I'm not a big fan of it unless you are designing MyClass to be specifically used only within shared_ptr objects, at which point I would insist that requirement be enforced.
It's a little ridiculous to put typedefs for every unrelated template instantiation that you might use with a given object. Just because you might put MyClass in a shared_ptr is not a good reason to typedef it there. You going to put typedefs for std::vector, map, list, unordered_map, set, deque,....etc, etc, etc?
But if MyClass extends shared_from_this and has private/protected constructors so that it can ONLY be created and immediately assigned to a shared_ptr then...sure...it's part of the interface.
If you're trying to avoid having to type out long parameter lists to instantiate a shared_ptr for a templated type with lots of parameters then a better bet is an EXTERNAL utility object just like shown in the article you cited:
template < typename T >
struct instantiate_shared_ptr { typedef shared_ptr<T> type; };
template < typename after typename > struct my_complex_template {};
typedef my_complex_template<some parameters> mct_1;
typedef instantiate_shared_ptr<mct_1>::type mct_1_sp;
Yes, especially if the name MyClass_sp is referred to in client code.
This is probably good practice, it makes it simpler if you decide to change the underlying class the typedef refers to at a later date and (arguably) saves typos as well as making code easier to read even if it never changes. The particular choice of name here MyClass_sp leaves a little to be desired in my opinion though.
Also it's worth thinking carefully if making the typedef public or private is most appropriate, i.e. is it part of your public interface?
It's good, IMO.
I used it a lot.
If I want to use a container which element is the type of the my template, I typedef it.
Such as,
template <typename T>
class MyClass {
private:
typedef std::list<T> SomeContainerType;
typedef SomeContainerType::iterator IteratorType;
Then if I find any other structure more suitable, such as a vector, I can change the type without touching too much code.
A better solution for smart pointer typedefs is to do them after the class definition in the header:
namespace N
{
class A
{
};
typedef std::tr1::shared_ptr<A> APtr;
}
This keeps your smart pointer defintion near your class definition while preventing you (and any developers using your code) from having to write code like A::APtr a(new A) (which just looks odd).
EDIT: Since he is concerned with a template class:
namespace N
{
template<class T, class L>
class A
{
};
template<class T, class L>
struct A_Instantiator
{
typedef std::tr1::shared_ptr<A<T, L> > APtr;
};
}
Consider the following example code:
class Foo
{
};
class Bar : public Foo
{
};
class FooCollection
{
protected:
vector<shared_ptr<Foo> > d_foos;
};
class BarCollection : public FooCollection
{
public:
vector<shared_ptr<Bar> > &getBars()
{
// return d_foos won't do here...
}
};
I have a problem like this in my current project. The client code uses BarCollection, which stores pointers to Bars in d_foos which is declared in FooCollection. I'd now like to expose the collection of pointers to Bars to the client code. I could just give the client code access to the vector of pointers to Foos and cast these to pointers to Bars in the client code, but this feels wrong since the client doesn't have to know about Foo's existence.
I could also define a get() member that retrieves objects from d_foos and casts them, but this feels quite clumsy. Preferably, I'd like to just return d_foos as a vector<shared_ptr<Bar> > &, but I cannot seem to do this.
It could also be that my design is just plain wrong. It seemed to most natural solution though, as Bar is a specialization of Foo and BarCollection is a specialization of FooCollection and they share functionality.
Could you suggest nice solutions to implement getBars in BarCollection or better design alternatives?
Edit:
Turns out my design was bad indeed. BarCollection is not a FooCollection, despite of requiring all of FooCollection's functionality. My current solution based on the answers below -- which is a lot cleaner -- is now:
class Foo
{
};
class Bar : public Foo
{
};
template<class T>
class Collection
{
vector<shared_ptr<T> > d_items;
};
typedef Collection<Foo> FooCollection;
class BarCollection : public Collection<Bar>
{
// Additional stuff here.
};
Thanks for all the excellent suggestions and examples!
I would suggest exposing iterators from your container classes, instead of the member container. That way it won't matter what the container type is.
The problem is you are trying to mix-and-match two different, pretty-much independent kinds of polymorphism in a way that won't work. The compile-time, type-safe polymorphism of templates won't allow you to substitute a base type for a derived type. C++'s template system makes no association between
class<Foo>
and
class<Bar>
One suggestion might be to create a Foo derived adapter that would cast down to the correct class:
template <class derived, class base>
class DowncastContainerAdapter
{
private:
std::vector< boost::shared_ptr<base> >::iterator curr;
std::vector< boost::shared_ptr<base> >::const_iterator end;
public:
DowncastContainerAdapter(/*setup curr & end iterators*/)
{
// assert derived actually is derived from base
}
boost::shared_ptr<derived> GetNext()
{
// increment iterator
++curr;
return dynamic_cast<base>(*curr);
}
bool IsEnd()
{
return (curr == end);
}
};
Note this class will have the same problem as an iterator, operation on the vector may invalidate this class.
Another thought
You may not realize it, but it may be perfectly fine to just return a vector of Foo. The user of Bar already must have full knowledge of Foo, since by including Bar.h they must get Foo.h through Bar.h. The reason being that for Bar to inherit from Foo, it must have full knowledge of the class via Foo.h. I would suggest rather than using the solution above, if it's possible make Foo (or a super class of Foo) an interface class and pass around vectors of pointers to that interface class. This is a pretty commonly seen pattern and won't raise the eyebrows that this wonky solution I came up with might :). Then again you may have your reasons. Good luck either way.
template<class T>
class MyContainer {
vector<shared_ptr<T> > d_foos;
public:
vector<shared_ptr<T> > & getVector();
};
class FooCollection : public MyContainer<Foo> {
};
class BarCollection : public MyContainer<Bar> {
};
The question is, why would you do that? If you give the user a collection of pointers to Bar, you assume, that there are only Bars in it, so internally storing the pointers in a collection to Foo makes no sense. If you store different subtypes of Foo in your collection of pointer to Foo, you cannot return it as a collection of pointers to Bar, since not all objects in there are Bars.
In the first case, (you know that you have only bars) you should use a templated approach as suggested above.
Otherwise, you have to rethink, what you really want.
Can you not replace this with a Collection templatized on either Foo / Bar?, something like this
class Collection<T> {
protected:
vector<shared_ptr<T> > d_foos;
};
typedef Collection<Foo> FooCollection;
typedef Collection<Bar> BarCollection;
Do you have a special need to have BarCollection derived from FooCollection? Because generally a BarCollection is not a FooCollection, usually a lot of the things that can be done with a FooCollection should not be done with a BarCollection. For example:
BarCollection *bc = new BarCollection();
FooCollection *fc = bc; // They are derived from each other to be able to do this
fc->addFoo(Foo()); // Of course we can add a Foo to a FooCollection
Now we have added a Foo object to what is supposed to be a BarCollection. If the BarCollection tries to access this newly added element and expects it to be a Bar, all kinds of ugly things will happen.
So usually you want to avoid this and don't have your collection classes derived from each other. See also questions about casting containers of derived types for more answers on this topic...
First of all, let's talk about shared_ptr. Do you know about: boost::detail::dynamic_cast_tag ?
shared_ptr<Foo> fooPtr(new Bar());
shared_ptr<Bar> barPtr(fooPtr, boost::detail::dynamic_cast_tag());
This is a very handy way. Under the cover it just performs a dynamic_cast, nothing fancy there but an easier notation. The contract is the same that the classic one: if the object pointed to does not actually is a Bar (or derived from it), then you get a null pointer.
Back to your question: BAD CODE.
BarCollection is NOT a FooCollection, as mentioned you are therefore in trouble because you could introduce other elements in the vector of pointers that Bar ones.
I won't extend on that though, because this is beyond the question at hand, and I think that we (as those trying to answer) should restrain ourselves from that.
You cannot pass a reference, but you can pass a View.
Basically, a View is a new object that act as a Proxy to the old one. It's relatively easy using Boost.Iterators from example.
class VectorView
{
typedef std::vector< std::shared_ptr<Foo> > base_type;
public:
typedef Bar value_type;
// all the cluttering
class iterator: boost::iterator::iterator_adaptor<
iterator,
typename base_type::iterator,
std::shared_ptr<Bar>
>
{
typename iterator_adaptor::reference dereference() const
{
// If you have a heart weakness, you'd better stop here...
return reinterpret_cast< std::shared_ptr<Bar> >(this->base_reference());
}
};
// idem for const_iterator
// On to the method forwarding
iterator begin() { return iterator(m_reference.begin()); }
private:
base_type& m_reference;
}; // class VectorView
The real problem here is of course the reference bit. Getting a NEW shared_ptr object is easy, and allow to perform a dynamic_cast as required. Getting a reference to the ORIGINAL shared_ptr but interpreted as the required type... is really not what I like to see in code.
Note:
There might be a way to do better than that using Boost.Fusion transform_view class, but I could not figure it out.
In particular, using transform_view I can get shared_ptr<Bar> but I can't get a shared_ptr<Bar>& when I dereference my iterator, which is annoying given that the only use of returning a reference to the underlying vector (and not a const_reference) is to actually modify the structure of the vector and the objects it contains.
Note 2:
Please consider refactoring. There have been excellent suggestions there.