'unique_ptr' is not a class template, implementing unique_ptr - c++

I have a piece of code that uses "unique_ptr", but
the Arduino environment does now know about:
#include <memory>
So i went to C++ reference
https://en.cppreference.com/w/cpp/memory/unique_ptr
Defined in header "memory"
template<
class T,
class Deleter = std::default_delete<T>
> class unique_ptr;
template <
class T,
class Deleter
> class unique_ptr<T[], Deleter>;
Figured that it doesn't take much to "implement".
My H file looks like this:
class state_deleter { // a deleter class with state
int count_;
public:
state_deleter() : count_(0) {}
template <class T>
void operator()(T* p) {
Serial.prinln("[deleted #");
delete p;
}
};
template <
class T,
class Deleter
> class unique_ptr<T[], Deleter>;
template <class T> class Circular_Buffer {
private:
unique_ptr<T[],state_deleter> buffer;
// i left non relevant code out
};
More info here:
https://cplusplus.com/reference/memory/unique_ptr/
Manages the storage of a pointer, providing a limited garbage-collection facility, with little to no overhead over built-in pointers (depending on the deleter used).
https://cplusplus.com/ref...nique_ptr/get_deleter/
So i added the above from CPP reference to the piece of code and by adding the "deleter", i removed error messages.
But still one remains:
'unique_ptr' is not a class template
I have implemented pieces of code from CPP reference before if i don't had access to it or needed a slightly adapted version and it worked.
Can it be done?
What makes this a "template class" a smart pointer?
class T,
class Deleter
not much too see here in this class definition.

Found Header files with the declaration of "Unique_ptr" here:
https://github.com/zouxiaohang/TinySTL/blob/master/TinySTL/Memory.h
and
https://github.com/microsoft/STL/blob/main/stl/inc/memory

Related

Getting type of a derived class at compile time in C++

I've been designing classes that all follow the idiom that their shared pointer type is available in their namespace using code like this:
class ClassName
{
public:
typedef std::shared_ptr<ClassName> ptr;
}
making it possible to write code like this:
ClassName::ptr p=std::make_shared<ClassName>();
Now, I'd like to factor that code into a base class. It'll let me magically add weak_ptr support in just one place, and will indicate which classes conform to this protocol, and generally make it easier to build out the capabilities.
Am I forced into using templates?
One way is to follow the enable_shared_from_this<> approach.
template <typename T>
class SmartPointer
{
public:
typedef std::shared_ptr<T> ptr;
typedef std::weak_ptr<T> wptr;
}
allowing me to define classes like this:
class ClassName:public SmartPointer<ClassName>
...
but it strikes me as clumsy to have to specify ClassName as the template parameter. What I'd like to do is be able to identify the type of the derived class at compile time, substituting in for derivedClassType() below:
class SmartPointer
{
public:
typedef std:shared_ptr<derivedClassType()> ptr;
typedef std:weak_ptr<derivedClassType()> wptr;
}
class ClassName: public SmartPointer
...
it seems like the compiler must know that information at compile time as a sort of implied template parameter... This has the added benefit of ensuring the type referenced is the derived class and not a base class.
Is there a syntax that would make this possible?
The approach used by enable_shared_from_this is called CRTP, the "curiously recurring template pattern." You need to specify the derived class; there is no way for a base class template to ask who is using it as a base class.
But you could inherit from enable_shared_from_this in your CRTP base and avoid specifying the derived class name twice.
So, I'm going to cheat by changing your syntax.
template<typename T>
using Ptr = T::template ptr<T>;
template<typename T>
using WPtr = T::template wptr<T>;
struct Pointerable {
template<typename T>
using ptr = std::shared_ptr<T>;
template<typename T>
using wptr = std::weak_ptr<T>;
};
class Foo : public Pointerable {
};
Ptr<Foo> x = std::make_shared<Foo>( ... );
WPtr<Foo> y = x;
here, the only purpose of Pointerable is to tag your types that you want to be used. Ptr<Foo> and WPtr<Foo> could be written to work on any class:
template<typename T>
using Ptr = std::shared_ptr<T>;
template<typename T>
using WPtr = std::weak_ptr<T>;
but I suppose you want to be able to tag objects as "managed by smart pointers" for whatever reason.
We could even make Pointerable completely empty, if you don't like that template boilerplate in it:
struct Pointerable {};
and add a traits class:
template<typename T>
struct is_pointerable : std::is_base_of<Pointerable, T> {};
which we then use:
template<typename T, typename=typename std::enable_if< is_pointerable<T>::value >::type >
using Ptr = std::shared_ptr<T>;
but I think the boilerplate works better -- SFINAE using seems overkill.

check template argument

I have a template class (A). How can I check if class T is derived from an abstract class IClass?
template <class T>
class A
{
//T have to be derived from abstract class IClass
} ;
thanks
Using static asserts and is_base_of from Boost, TR1 or C++11:
template <class T>
class A {
public:
BOOST_STATIC_ASSERT(( boost::is_base_of<IClass, T>::value ));
};
What you're trying to do is referred to as a template concept check. These were going to be a feature in C++11 but the standards committee cut it.
You can still do it though, it's just not as clean as it might otherwise be. Bjarne Stroustrup explains how to do this on his FAQ: http://www2.research.att.com/~bs/bs_faq2.html#constraints
Specifically he gives this example:
template<class T, class B> struct Derived_from {
static void constraints(T* p) { B* pb = p; }
Derived_from() { void(*p)(T*) = constraints; }
};
Then you just declare a dummy parent inside your class so that it'll trip a compiler error:
template <class T> class A : Derived_from<T,IClass> { ... }
Stroustrup mentioned that this actually tests for conversion, not for inheritance. There might be a way to test specifically for inheritance only, if that's what you need.

How to properly declare a self-referencing template type?

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.

Templated list of templated objects in C++

I'm trying to create a list of objects, where each object also stores 'ownership' - ie, it knows which list holds it.
In a non-template situation, it's straightforward:
class FooList; // forward declaration
class FooItem
{
public:
FooList *owner;
...
};
class FooList: private std::list<FooItem>
{
...
};
However, the list class is a template, based on the contained object type, and I'm struggling to work out how to specify this. I reckon the FooItem class now needs to be a template because the type of 'owner' can vary:
template <class E> class FooItem
{
public:
std::list<E> *owner;
};
template <class E> class FooList: private std::list<E>
{
...
};
But, now given my two templates, how can I define the new types I want? The snippet below is what I think I need, but it gives "error: Multiple declaration for BarItem".
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
EDIT:
Thanks to those who pointed out the issue of std::list<E> instead of std::list<FooItem<E> >
EDIT 2:
Renamed classes to Base, Derived, BaseList, DerivedList.
My real problem was the 'circular typedef'. After some more tinkering, I think this will do what I require. It creates a 'real' BarItem class rather than just a typedef, but seems to at least compile now.
template <class E> class BaseList; // forward declaration
template <class E> class Base
{
public:
BaseList< Base<E> > *owner;
};
template <class E> class BaseList: private std::list< E >
{
};
// typedef Base<BaseList<Derived> > Derived; //This won't compile, unsurprisingly.
class Derived : public Base < BaseList<Derived> > // Surprisingly, this seems to.
{
...
};
typedef BaseList<Derived> DerivedList;
Does this seem to make sense? Is it a common idiom or something horrible?
Are you sure you didn't want:
template <class E> class FooItem
{
public:
std::list< FooItem<E> > *owner; // owned by a list of FooItem<E>, not raw E
};
template <class E> class FooList: private std::list< FooItem<E> > // is a list of FooItem<E>, not raw E
{
...
};
The error you are getting is because you forward declare the class BarItem but later try to redefine that name using typedef. Not sure what you're trying to accomplish, but you'll need to introduce a third name. Maybe you meant:
class Bar;
typedef FooItem<Bar> BarItem;
typedef FooList<Bar> BarList;
EDIT: The new code you've posted certainly compiles, but seems very awkward (for one thing, the naming seems really confusing). Perhaps you should ask a new question with a more concrete example of why you think you need an 'item which is an item of lists of itself' and see if others can come up with a less awkward design.
Is that last set of typedef statements correct? You posted this:
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
It's somewhat recursive, right? The first statement says there's a class BarItem that exists elsewhere. The second statement says that the type FooList<BarItem> (a list of BarItem objects) can also be referred to as BarList. The third statement says that the type FooItem<BarList> can also be referred to as BarItem, but BarItem was already defined as a type by the class BarItem statement.
So you're saying that BarItem is a type all to itself (via the class statement), but you're also saying that BarItem is an alias for the type FooItem<BarList>. Hence the conflict.
If you just want to generalize your first approach to a templated FooItem class, it would look like this:
template <class E> class FooList; // forward declaration
template <class E> class FooItem
{
public:
FooList<E> *owner;
...
};
template <class E> class FooList: private std::list< FooItem<E> >
{
...
};
If that is not what you want I'm not sure what exactly you are attempting to do.

Extending class template

How would I do to extend a template class, for example vector? The below code does not work. The compiler whines about 'Vector' not being a template.
template <typename T>
class Vector<T> : public std::vector<T>
{
public:
void DoSomething()
{
// ...
}
};
Your syntax is wrong; you need to use:
template <typename T>
class Vector : public std::vector<T>
That said, you should not extend the standard library containers via inheritance, if for no other reason then because they do not have virtual destructors and it is therefore inherently unsafe.
If you want to "enhance" std::vector, do so using composition (i.e., with a member variable of std::vector type) or use non-member functions to provide your additional functionality.
This has nothing to do with extending another class. The problem is your own derived class.
You define a class template like this:
template <typename T>
class Vector
{
...
and not
template <typename T>
class Vector<T>
{
...