I have a function that potentially moves a generic argument but through their members. What of these options is more correct:
This seems the more natural but it is strange because the argument is potentially moved twice [a], which is odd because the object can become invalid.
template<class T>
void fun(T&& t){
myhead_ = std::forward<T>(t).head_;
myrest_ = std::forward<T>(t).rest_;
}
This can't be incorrect but it may not be moving anything.
template<class T> void fun(T&& t){
myhead_ = std::forward<decltype(t.head_)>(t.head_);
myrest_ = std::forward<decltype(t.rest_)>(t.rest_);
}
This seems correct but too much code.
template<class T> void fun(T& t){
myhead_ = t.head_;
myrest_ = t.rest_;
}
template<class T> void fun(T&& t){
myhead_ = std::move(t.head_);
myrest_ = std::move(t.rest_);
}
[a] This statement is incorrect as #Angew pointed out, it only looks as if it is moved twice. std::forward (like std::move) doesn't actually move anything. At most the member is moved (by the subsequent operation decltype(myhead)::operator= but that is precisely the objective.)
Your first code is perfectly fine:
template<class T>
void fun(T&& t){
myhead_ = std::forward<T>(t).head_;
myrest_ = std::forward<T>(t).rest_;
}
That is because the standard guarantees that when doing a.b and a is an xvalue (such as a forwarded rvalue reference), the result of a.b is also an exvalue (i.e. can be moved from). Also note that std::forward and std::move do not do any actual moving themselves, they're just casts. So there is no risk in moving from t twice in your code.
Related
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.)
Is it possible to detect the container type from the iterator type?
For example,
#include<traits>
int main(){
static_assert(std::is_same<
container_of<std::vector<double>::iterator>::type, std::vector<double>>{});
static_assert(std::is_same<
container_of<std::list<int>::iterator>::type, std::list<int>>{});
}
(Of course some iterators type will not give a container (or not give a unique container), for example a raw pointer or a stream iterator, but in those cases it can soft-SFINAE-fail.)
The first attempt is
template<class T, template<class> class Cont> Cont<T> aux(typename Cont<T>::iterator it);
template<class Iterator> struct container_of{
using type = decltype(aux(Iterator{}));
};
However, it doesn't work because the compiler can't detect the type of T (it is not in a deductible context).
Motivation: I want to detect whether the associated container of an iterator has a .data() member.
Instead of your primitive being an iterator, make your primitive be a range.
template<class It, bool Contiguous, class D=void>
struct range_t {
using Self = std::conditional< !std::is_same<D, void>, D, range_t >;
It b, e;
It begin() const { return b; }
It end() const { return e; }
Self without_front( std::size_t i = 1 ) const {
return {std::next(begin(), i), end()};
}
Self without_back( std::size_t i = 1 ) const {
return {begin(), std::prev(end(), i)};
}
bool empty() const { return begin()==end(); }
std::size_t size() const { return std::distance( begin(), end() ); }
};
template<class It>
struct range_t<It, true, void>:
range_t<It, false, range_t<It, true>>
{
using Base = range_t<It, false, range_t<It, true>>;
range_t( It b, It e ):Base(b,e) {}
auto* data() const {
if (empty()) return nullptr;
return std::addressof(*this->begin()); }
}
};
Track (manually) what containers are contiguous:
template<class T, class=void>
struct is_contiguous_container : std::false_type{};
template<class T>
struct is_contiguous_container<T const, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T volatile, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T const volatile, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T, std::enable_if_t< has_data_ptr<T>{} >>:
std::true_type{};
template<class T, std::size_t N>
struct is_contiguous_container<T[N],void> : std::true_type{};
The contiguous containers are array, std::array and std::vector, so not much to track. range_t< ?, true, ? > is also contiguous. Just write has_data_ptr, that is true iff T.data() returns a pointer to non-void.
template<class C>
auto range( C&& c ) {
using std:begin; using std::end;
auto b = begin(c), e = end(c);
using It = decltype(b);
using R = range_t<It, is_contiguous_container<std::remove_reference_t<C>>{}>;
return R{ b, e };
}
range now smartly converts a container into a range_t, keeping track of if it is contiguous or not.
range_t supports r.without_front( r.size()/2 ) to divide and conquer.
When a range is contiguous, just call .data() on it. When it isn't, don't.
In your application if you just want to know whether the container has a .data() member, it might be enough for you to check if it is random access (using std::iterator_traits<Iter>::iterator_category()).
Otherwise, I think you might be able to use a combination of the technique in: How to check if two types come from the same templated class and partial specialization for every standard container type.
Or wait for c++17 which has a new contiguous iterator concept: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html
What I am doing at the moment is to manually register all (some really) of the iterators that are contiguous.
Since I will always need this in combination with some way to extract the raw pointer, I directly code a single function called data that returns the pointer.
The code is not funny, it considers std::vector<>::iterator, std::basric_string<>::iterator, for illustration (to show that it will always be incomplete) I also added boost::static_vector<>, raw pointer and anything convertible to a pointer. (boost::array<>::iterator and std::array<>::iterator and begin/end(std::valarray) are effectively included because the iterators are pointers).
I also had to include the const_iterator cases.
#include<type_traits>
#include<vector> // the code below needs to know about std::vector
#include<boost/container/static_vector.hpp> // ... and all possible contigous containers :(
template<
class ContiguousIterator, // well ProbablyContiguos
typename = std::enable_if_t<
/**/std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{}
or std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::const_iterator>{}
or std::is_same<ContiguousIterator, typename std::basic_string<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{}
or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::iterator>{}
or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::const_iterator>{}
// many many other possible iterators :(
or std::is_pointer<ContiguousIterator>{}
or std::is_constructible<typename std::iterator_traits<ContiguousIterator>::pointer, ContiguousIterator>{}
>
>
typename std::iterator_traits<ContiguousIterator>::pointer
data(ContiguousIterator const& it){return std::addressof(*it);}
int main(){
std::vector<double> v(30);
v[0] = 10.;
assert( *data(v.begin()) == 10. );
}
Feedback is welcomed.
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 am wondering if c++11/c++14 would/already support something like vector<auto>?
If not, Is there any reason?
It's not supported directly, and not immediately clear exactly what you want it to do.
Comments have already mentioned a couple of possibilities (such as Boost any and variant classes) for creating heterogeneous collections. I hope this isn't what you were after, because heterogeneous collections fit poorly with C++ so using them is ugly and clumsy. I suppose there are cases/situations where these really would be the best choices available, but at least in my experience, those cases are fairly rare.
Another possible interpretation of what you might want would be a vector that (like auto in general) holds exactly one type, but that type is deduced from the initializer, so if you initialized the vector from some ints, you'd get a vector<int>, and if you initialized it from some strings, you'd get a vector<string>, and so on. Although the language doesn't support that directly, it is pretty easy to simulate it to at least some degree. Template classes can't/don't ever deduce template parameters, but template functions do/can. Therefore, we can create a tiny function template to take some initializers, deduce their type, and return a vector of that type. For example:
template <class T>
std::vector<T> make_vector(std::initializer_list<T> init) {
return std::vector<T>(init);
}
This returns a vector<T> (with T deduced from the type of data in the initializer list), so you can do things like:
auto a = make_vector({ 1, 2, 3, 4 }); // a -> vector<int>
auto b = make_vector({ 1.0, 2.0, 3.0 }); // b -> vector<double>
auto c = make_vector({ "1"s, "2"s, "3"s }); // c -> vector<std::string>
That last one requires a user-defined literal operator that's new in C++14 (which many compilers don't yet support). The rest should be fine with C++11.
There has also been some discussion (and a proposal in N3602) of adding a capability (perhaps to C++17) where you'd be able to define something like the make_vector above, but as something like a templated constructor for the class. This would let you use argument deduction on the constructor to deduce the template parameter for the class as a whole, so you'd be able to do something like:
X x(1); // deduces as X<int>
X x(2.0) // deduces as X<double>
Warning though: this has been proposed but not accepted. It may (easily) never be accepted--and even if it is, it may be altered significantly before that happens.
No, not in C++11 or C++14, which are already finished and published.
But it's possible that vector<auto> and similar things like tuple<auto...> will be in C++17 as part of the Concepts work.
It follows quite naturally from the fact that std::vector<T> can be used in function templates and class template partial specializations where T is a template parameter, and also from the fact that polymorphic lambdas allow auto as a function parameter type (which is shorthand for a function template with deduced parameters).
The Concepts TS allows a "generic function" to be declared like:
auto func(auto arg);
Since you can have a function template like this:
template<typename T>
auto func(std::vector<T> v);
it makes sense to extend the generic function syntax to allow:
auto func(std::vector<auto> v);
and once you allow that in a function declaration, it should also be possible to allow it in variable declarations:
std::vector<auto> v = function_returning_vector_of_something();
The reason it isn't in C++11 is that auto was new, and it would have been too ambitious to try and make it do too much. In C++14 polymorphic lambdas were new, and again, expanding the uses of auto any further would have been ambitious.
For C++17 we have more experience with using auto in real code, and compiler writers are familiar with implementing it and know what is possible without too much effort.
A boost::any can store an instance of any type that can be copied, which is a lot of types.
In order to get the data out of your any, you have to know the exact type you stored in it.
Writing a simple any isn't hard:
#include <memory>
#include <utility>
struct any_internal {
virtual any_internal* clone() const = 0;
virtual ~any_internal() {};
};
template<class T>
struct any_details;
class any {
std::unique_ptr<any_internal> internal;
public:
any() = default;
any( any && ) = default;
any( any const&& o):any(o) {}
any( any & o ):any( const_cast<any const&>(o) ) {}
any& operator=( any && ) = default;
any& operator=( any const&& o ) { return this->operator=( o ); };
any& operator=( any & o ) { return this->operator=( const_cast<any const&>(o) ); };
any( any const& o ):internal( o.internal?o.internal->clone():nullptr ) {}
any& operator=( any const& o ) {
any tmp(o);
using std::swap;
swap( internal, tmp.internal );
return *this;
}
template<class U>
void reset( U&& o );
template<class U, class... Args>
void emplace( Args&&... args );
template<class U>
any( U&& o );
template<class U>
any& operator=(U&& o);
template<class T> T* get();
template<class T> T const* get() const;
template<class T> T* fast_get();
template<class T> T const* fast_get() const;
explicit operator bool() const { return internal!=nullptr; }
};
template<class T>
struct any_details : any_internal {
T t;
template<class...Args>
any_details( Args&&... args ):t(std::forward<Args>(args)...) {}
any_internal* clone() const override { return new any_details<T>{t}; }
};
template<class U, class... Args>
void any::emplace( Args&&... args ) {
internal.reset( new any_details<U>( std::forward<Args>(args)... ) );
}
template<class U>
void any::reset( U&& o ) {
emplace<typename std::decay<U>::type>( std::forward<U>(o) );
}
template<class U>
any::any( U&& o ) {
reset( std::forward<U>(o) );
}
template<class U>
any& any::operator=(U&& o) {
reset( std::forward<U>(o) );
return *this;
}
template<class T> T* any::get() {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::get() const {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T* any::fast_get() {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::fast_get() const {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
and a std::vector<any> behaves much like you might want a std::vector<auto> to do.
Increased efficiency can be achieved via small buffer optimizations (ie, store the T within the any if the t is small, instead of using the heap).
You'd probably also want to split get from fast_get, where get does a dynamic_cast and fast_get does a static_cast, again for efficiency. (When you know for certain, you can fast_get)
Basically this is a gussied up void*.
I thought that template specializations were fully independent entities and could have whatever they wanted. But VC++ threw me an error when I made the return type of a specialization different to the return type of the original template. Is that really Standard? I worked around it easily by moving the function body into a static class.
There is no function template partial specialization, because there's overloading of functions (and function templates. However, function overloading is much more limited than template specialization, so what you usually do, is to fall back on class template specializations:
template< typename R, typename T >
struct foo_impl {
static R foo(T)
{
// ...
return R(); // blah
}
};
template< typename T >
struct foo_impl<void,T> {
static void foo(T)
{
// ...
}
};
template< typename R, typename T >
R foo(T obj);
{
return foo_impl<R,T>::foo(obj); // fine even if R is void
}
Function specialization is weird and almost non-existent. It's possible to fully specialize a function, while retaining all types - i.e. you're providing a custom implementation of some specialization of the existing function. You can not partially specialize a templated function.
It's likely that what you're trying to do can be achieved with overloading, i.e.:
template <typename T> T foo(T arg) { return T(); }
float foo(int arg) { return 1.f; }