I am using a std::shared_ptr to point to a Node
template<typename T>
class A
{
class Node
{
T data;
std::shared_ptr<Node> link;
Node(T data, std::shared_ptr<Node> link);
};
void push(T data);
std::shared_ptr<Node> top;
};
template<typename T>
A<T>::Node::Node(T data, std::shared_ptr<typename A<T>::Node> link) :
data(data), link(link)
{
}
template<typename T>
void A<T>::push(T item)
{
if (top == nullptr)
{
top = std::make_shared<typename A<T>::Node>(new typename
A<T>::Node(item, nullptr));
}
else
{
top = std::make_shared<typename A<T>::Node>(new typename A<T>::Node(item, top));
}
}
The resulting declarations and definitions results in the compiler error
Severity Code Description Project File Line Suppression State
Error C2664 'Stack::Node::Node(const Stack::Node &)': cannot convert argument 1 from 'Stack::Node *' to 'const Stack::Node &' memory 901
What do I need to change to conform to <memory>?
A constructor of std::shared_ptr<T> accepts a pointer to T which you have created with new.
The function std::make_shared<T>(args...) does the new for you instead. The arguments you pass to make_shared will be passed on to the constructor of T. So you should almost never pass it a pointer created by new (unless you really want to new a T, and then pass that pointer as an argument to create another T!).
So for example, instead of:
std::make_shared<typename A<T>::Node>(
new typename A<T>::Node(item, top))
do just:
std::make_shared<typename A<T>::Node>(item, top)
(By the way, you don't actually need most of those typename A<T>:: qualifiers. Just plain Node is in scope whenever you're in the scope of A<T> or A<T>::Node, both in the class definitions and member definitions of that class after the member name. A<T>::Node without the typename would also work in those contexts because of the "member of the current instantiation" rule.)
Related
I have seen an idiom for using Derived type traits in the base class of a CRTP pattern that looks like this:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
template <typename T>
struct Derived1 : Base<Derived1<T>>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <typename T>
struct traits<Derived1<T>> {
using size_type = size_t;
};
int main()
{
using T = float;
Derived1<T> d1;
d1.print();
}
My understanding is that the purpose of the idiom is to delay the instantiation of the Base class's size_type. What I am confused by is the fact that this pattern only seems to work if the derived class is itself templated. For instance, if we change the code to:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <>
struct traits<Derived1> {
using size_type = size_t;
};
int main()
{
Derived1 d1;
d1.print();
}
then we get the error
prog.cc: In instantiation of 'struct Base<Derived1>':
prog.cc:21:19: required from here
prog.cc:18:58: error: invalid use of incomplete type 'struct traits<Derived1>'
using size_type = typename traits<Derived>::size_type;
^
prog.cc:14:8: note: declaration of 'struct traits<Derived1>'
struct traits;
^~~~~~
prog.cc: In function 'int main()':
prog.cc:33:9: error: 'Derived1' is not a template
Derived1<float> d1;
Could somebody give me an explanation indicating why the templated derived class compiles, but the untemplated class does not?
The issue you're seeing has nothing to do with CRTP.
Here's what the standard mentions.
If a class template has been declared, but not defined, at the point of instantiation (13.7.4.1),
the instantiation yields an incomplete class type (6.7). [Example:
template<class T> class X; X<char> ch; // error: incomplete type
X<char>
Your traits has only been declared at the point of instantiation of Base<Derived>, hence as per the standard(see above extraction from the standard), struct traits<Derived> yields an incomplete type.
You should reorder the code so that it sees the traits<Derived> specialization when Base<Derived> gets instantiated.
The compilation error you are seeing has nothing to do with CRTP, it's just a bit of a mish-mash of dependencies.
In the code without the templation, your "Base" struct needs the definition of the specialized "traits" struct but it only appears afterwards, so it tries to use the incomplete type it saw in the declaration above.
To get the code to work you need to have the "traits" specialization before the Base declaration, which requires you to also add a declaration of Derived 1, here is a compiling code:
class Derived1;
template<typename Derived>
struct traits;
template <>
struct traits<Derived1> {
using size_type = size_t;
};
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
int main()
{
Derived1 d1;
d1.print();
}
I have a C++11 template that can be specialized with an arbitrary type parameter.
template<class ElementType>
class Foo
How do I declare a constructor that appears for the compiler's consideration only when ElementType is e.g. const uint8_t?
That is, I have a bunch of constructors that are generic over any ElementType, but I also want to have constructors that are only considered when ElementType is specialized in a particular way. (Allowing those constructors to be selected for other types would be unsafe.)
So far std::enable_if examples that I've found have been conditional on the types of the arguments of the constructors.
template<class ElementType>
struct Foo
{
template <typename T = ElementType>
Foo(typename std::enable_if<!std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
template <typename T = ElementType>
Foo(typename std::enable_if<std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
};
int main()
{
Foo<int> a{}; // ok, calls first constructor
Foo<const uint8_t> b{}; // ok, calls second constructor
}
wandbox example
You can break the class into two classes. The derived class' purpose is to be able to specialize constructors for different types. E.g.:
#include <cstdio>
#include <cstdint>
template<class ElementType>
struct Foo_
{
Foo_() { std::printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class ElementType>
struct Foo : Foo_<ElementType>
{
using Foo_<ElementType>::Foo_; // Generic version.
};
template<>
struct Foo<uint8_t> : Foo_<uint8_t>
{
Foo() { std::printf("%s\n", __PRETTY_FUNCTION__); } // Specialization for uint8_t.
};
int main(int ac, char**) {
Foo<int8_t> a;
Foo<uint8_t> b;
}
The benefit of using the derived class here compared to enable_if is that:
The class can be partially specialized.
Only one specialization of the class is chosen for particular template parameters, rather than a set of constructors. When adding specializations for new types the existing enable_if expressions may need to be changed to make them more restrictive to avoid function overload set resolution ambiguity.
Consider simplified linked list implementation in C++11
template<typename T>
struct list
{
struct node
{
T value;
std::unique_ptr<node> next;
};
std::unique_ptr<node> root;
};
Now, if I have linked list, which cleans itself in its destructor using std::unique_ptr's destructor. The destruction could be recursive if compiler is not clever enough in optimalizations. If we had trillions elements in our list, it could be an issue (stack overflow).
So, to help the compiler I would not use std::default_delete for std::unique_ptr, but rather bring my own implementation
template<typename T>
struct my_list_delete
{
void operator()(T* ptr) const
{
std::stack<T*> nodes;
// use explicit stack instead of call stack in recursion
}
};
And all nodes would be std::unique_ptr<node, my_list_delete<node>>. It is nice, but I have to write more code for every std::unique_ptr I have. Instead, I could partially specialize std::default_delete!
namespace std
{
template<typename T>
struct default_delete<typename list<T>::node>
{
void operator()(typename list<T>* node) const
{
}
};
}
But this does not work. As long as I know the type used to instantiate list, I can plug that in. But if I want to make it generic, I am stuck at
error C2764: 'T': template parameter not used or deducible in partial specialization 'std::default_delete<list<T>::node>'
I there a way to get around this in C++11? I was thinking about using SFINAE
namespace std
{
template<typename T, typename = std::enable_if</*T is list*/>::type>
struct default_delete<T>
{
void operator()(T* node) const
{
}
};
}
A simple workaround would be to write a using declaration for that type:
using node_ptr = std::unique_ptr<node, my_list_delete<node>>;
You can "unnest" the inner class:
template <typename T> struct list_node {
T value;
std::unique_ptr<node> next;
};
template<typename T> struct list {
using node = list_node<T>;
std::unique_ptr<node> root;
};
namespace std {
template<typename T> struct default_delete<list_node<T>> {
void operator()(typename list<T>* node) const { }
};
}
default_delete<list<T>::node>()(...); // works
Regardless of the fact that copying a unique_ptr makes sense or not*, I tried to implement this kind of class, simply wrapping a std::unique_ptr, and got into difficulty exactly where the copy is taken, in the case of a smart pointer to base and the stored object being a derived class.
A naive implementation of the copy constructor can be found all over the internet (data is the wrapped std::unique_ptr):
copyable_unique_ptr::copyable_unique_ptr(const copyable_unique_ptr& other)
: data(std::make_unique(*other.get()) // invoke the class's copy constructor
{}
Problem here is, that due to the left out template arguments, is that the copy creates an instance of the type T, even if the real type is U : T. This leads to loss of information on a copy, and although I understand perfectly well why this happens here, I can't find a way around this.
Note that in the move case, there is no problem. The original pointer was created properly somewhere in user code, and moving it to a new owner doesn't modify the object's real type. To make a copy, you need more information.
Also note that a solution employing a clone function (thus infecting the type T's interface) is not what I would find to be acceptable.
*if you want a single owning pointer to a copyable resource this can make sense and it provides much more than what a scoped_ptr or auto_ptr would provide.
After some struggling with getting all the magic incantations right so that a good C++ compiler is satisfied with the code, and I was satisfied with the semantics, I present to you, a (very barebones) value_ptr, with both copy and move semantics. Important to remember is to use make_value<Derived> so it picks up the correct copy function, otherwise a copy will slice your object. I did not find an implementation of a deep_copy_ptr or value_ptr that actually had a mechanism to withstand slicing. This is a rough-edged implementation that misses things like the fine-grained reference handling or array specialization, but here it is nonetheless:
template <typename T>
static void* (*copy_constructor_copier())(void*)
{
return [](void* other)
{ return static_cast<void*>(new T(*static_cast<T*>(other))); };
}
template<typename T>
class smart_copy
{
public:
using copy_function_type = void*(*)(void*);
explicit smart_copy() { static_assert(!std::is_abstract<T>::value, "Cannot default construct smart_copy for an abstract type."); }
explicit smart_copy(copy_function_type copy_function) : copy_function(copy_function) {}
smart_copy(const smart_copy& other) : copy_function(other.get_copy_function()) {}
template<typename U>
smart_copy(const smart_copy<U>& other) : copy_function(other.get_copy_function()) {}
void* operator()(void* other) const { return copy_function(other); }
copy_function_type get_copy_function() const { return copy_function; }
private:
copy_function_type copy_function = copy_constructor_copier<T>();
};
template<typename T,
typename Copier = smart_copy<T>,
typename Deleter = std::default_delete<T>>
class value_ptr
{
using pointer = std::add_pointer_t<T>;
using element_type = std::remove_reference_t<T>;
using reference = std::add_lvalue_reference_t<element_type>;
using const_reference = std::add_const_t<reference>;
using copier_type = Copier;
using deleter_type = Deleter;
public:
explicit constexpr value_ptr() = default;
explicit constexpr value_ptr(std::nullptr_t) : value_ptr() {}
explicit value_ptr(pointer p) : data{p, copier_type(), deleter_type()} {}
~value_ptr()
{
reset(nullptr);
}
explicit value_ptr(const value_ptr& other)
: data{static_cast<pointer>(other.get_copier()(other.get())), other.get_copier(), other.get_deleter()} {}
explicit value_ptr(value_ptr&& other)
: data{other.get(), other.get_copier(), other.get_deleter()} { other.release(); }
template<typename U, typename OtherCopier>
value_ptr(const value_ptr<U, OtherCopier>& other)
: data{static_cast<pointer>(other.get_copier().get_copy_function()(other.get())), other.get_copier(), other.get_deleter()} {}
template<typename U, typename OtherCopier>
value_ptr(value_ptr<U, OtherCopier>&& other)
: data{other.get(), other.get_copier(), other.get_deleter()} { other.release(); }
const value_ptr& operator=(value_ptr other) { swap(data, other.data); return *this; }
template<typename U, typename OtherCopier, typename OtherDeleter>
value_ptr& operator=(value_ptr<U, OtherCopier, OtherDeleter> other) { std::swap(data, other.data); return *this; }
pointer operator->() { return get(); }
const pointer operator->() const { return get(); }
reference operator*() { return *get(); }
const_reference operator*() const { return *get(); }
pointer get() { return std::get<0>(data); }
const pointer get() const { return std::get<0>(data); }
copier_type& get_copier() { return std::get<1>(data); }
const copier_type& get_copier() const { return std::get<1>(data); }
deleter_type& get_deleter() { return std::get<2>(data); }
const deleter_type& get_deleter() const { return std::get<2>(data); }
void reset(pointer new_data)
{
if(get())
{
get_deleter()(get());
}
std::get<0>(data) = new_data;
}
pointer release() noexcept
{
pointer result = get();
std::get<0>(data) = pointer();
return result;
}
private:
std::tuple<pointer, copier_type, deleter_type> data = {nullptr, smart_copy<T>(), std::default_delete<T>()};
};
template<typename T, typename... ArgTypes>
value_ptr<T> make_value(ArgTypes&&... args)
{
return value_ptr<T>(new T(std::forward<ArgTypes>(args)...));;
}
Code lives here and tests to show how it should work are here for everyone to see for themselves. Comments always welcome.
I'm building a large project on Debian 6.0.6 (with gcc 4.4.5) that was initially built in Microsoft VS (2008, I think).
What seems to be the problem is that when I declare a member as
typedef typename std::set<T>::iterator iterator, and then later use this iterator, gcc appears to interpret this as (const T*).
The part of the class containing the typename designation:
template <class entityType>
class entityArray
{
private: std::set<entityType> m_array;
public: typedef typename std::set<entityType>::iterator iterator;
...
public:
entityType* At( const char* name);
...
};
plus a few other classes that are needed for the discussion:
class entity
{
private:
entity* m_parent;
int m_ncid;
std::string m_name;
public:
entity () { m_ncid = 0; m_parent = NULL;}
virtual ~entity () {};
...
};
class attribute : public entity
{
public:
attribute(){};
virtual ~attribute(){};
};
class var : public entity
{
private:
entityArray<attribute> m_atts;
public:
var(){}
virtual ~var(){}
...
};
class dim : public entity
{
public:
dim() {};
virtual ~dim() {};
};
class group : public entity
{
private:
entityArray<var> m_vars;
entityArray<dim> m_dims;
...
public:
dim* DimAt( const char* dimname ) { return m_dims.At(dimname);}
};
Now an iterator is initialized through a call to the function DimAt which in turn calls At. The At function in the first class is defined as:
template <class entityType>
entityType* entityArray<entityType>::At( const char* name )
{
entityType dummy;
iterator iter;
entityType* ptr;
... define dummy ...
iter = m_array.find( dummy );
ptr = (iter != m_array.end()) ? &(*iter) : NULL;
return ptr;
}
Compiling the above produces
error: invalid conversion from const dim* to dim*., referring to &(*iter).
I realize that typename is required for declaring iterator, since the type is a dependent and qualified name, but I don't see why this substitution (const *) is being performed by the compiler. I would appreciate any help that you could provide. Thanks!
This has absolutely nothing to do with typename.
The standard allows std::set<T>::iterator and std::set<T>::const_iterator to be the same type, and with GCC the types are the same.
The reason is that modifying an element of a std::set e.g. by *iter = val might invalidate the ordering of the set elements, breaking the invariant that the elements of the set are always in order. By making the iterator type a constant iterator instead of a mutable iterator it's not possible to alter the element, preventing you from corrupting the set's ordering.
So with GCC's implementation, when you dereference the iterator using *iter you get a const entitType& and when you take its address using &*iter you get a const entityType*