I try to construct a vector with unique_ptr. But I do not find a direct way. The following code does not compiles. The error is:Call to implicitly-deleted copy constructor of 'std::__1::unique_ptr >':
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
class test1{
public:
test1(){};
test1(test1&&)=default;
};
int main(int argc, const char * argv[]) {
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec{move(us)};
return 0;
}
This make_vector is a function that takes any number of arguments, and perfect-forwards them into a vector.
// get the first type in a pack, if it exists:
template<class...Ts>
struct first {};
template<class T, class...Ts>
struct first<T,Ts...>{
using type=T;
};
template<class...Ts>
using first_t=typename first<Ts...>::type;
// build the return type:
template<class T0, class...Ts>
using vector_T =
typename std::conditional<
std::is_same<T0, void>::value,
typename std::decay<first_t<Ts...>>::type,
T0
>::type;
template<class T0, class...Ts>
using vector_t = std::vector< vector_T<T0, Ts...> >;
// make a vector, non-empty arg case:
template<class T0=void, class...Ts, class R=vector_t<T0, Ts...>>
R make_vector( Ts&&...ts ) {
R retval;
retval.reserve(sizeof...(Ts)); // we know how many elements
// array unpacking trick:
using discard = int[];
(void)discard{0,((
retval.emplace_back( std::forward<Ts>(ts) )
),void(),0)...};
return retval; // NRVO!
}
// the empty overload:
template<class T>
std::vector<T> make_vector() {
return {};
}
use:
std::vector<std::unique_ptr<test1>> vec =
make_vector(
std::move(u1), std::move(u2)
);
live example
I polished it a bit. It will deduce the return type if you pass it 1 or more args and you don't pass it a type. If you pass it a type, it will use that type. If you fail to pass it a type or any args, it will complain. (if you forward packs, or are storing it in a particular type, I'd always give it a type).
A further step could be done, where we do return type deduction to eliminate the requirement to specify the type even in the empty case. This may be required in your use case, I don't know, but it matches how you don't need to specify the type of a {}, so I thought I'd toss it out there:
template<class...Ts>
struct make_vec_later {
std::tuple<Ts...> args; // could make this `Ts&&...`, but that is scary
// make this && in C++14
template<class T, size_t...Is>
std::vector<T> get(std::index_sequence<Is...>) {
return make_vector<T>(std::get<Is>(std::move(args))...);
}
// make this && in C++14
template<class T>
operator std::vector<T>(){
return std::move(*this).template get<T>( std::index_sequence_for<Ts...>{} );
}
};
template<class...Ts>
make_vec_later<Ts...> v(Ts&&...ts) {
return {std::tuple<Ts...>(std::forward<Ts>(ts)...)};
}
this does rely on a C++14 feature of index_sequence, but those are easy to rewrite in C++11 if your compiler doesn't have it yet. Simply google it on stack overflow, there are a myriad of implementations.
Now the syntax looks like:
std::vector<std::unique_ptr<test1>> vec =
v(std::move(u1));
where the list of arguments can be empty.
Live example
Supporting variant allocators is left as an exercise to the user. Add another type to make_vector called A, and have it default to void. If it is void, swap it for std::allocator<T> for whatever type T is chosen for the vector. In the return type deduction version, do something similar.
You're calling the vector constructor ((7) on the linked page) that takes an initializer_list<T> argument. An initializer_list only allows const access to its elements, so the vector must copy the elements, and this, of course, fails to compile.
The following should work
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec;
vec.push_back(move(us));
// or
vec.push_back(std::unique_ptr<test1>(new test1()));
// or
vec.push_back(std::make_unique<test1>()); // make_unique requires C++14
You could use the vector constructor that takes two iterators, but the solution is still not a one-liner because it requires you to define a temporary array that you can then move from.
std::unique_ptr<test1> arr[] = {std::make_unique<test1>()};
std::vector<std::unique_ptr<test1>> vec{std::make_move_iterator(std::begin(arr)),
std::make_move_iterator(std::end(arr))};
Related
I'm looking for a solution using only native C++ language features (up to C++17) for accomplishing the following:
std::array<Type, unsigned int Elem> array_{Type(), // 1 - Call constructor on Type()
Type(), // 2 - ...
... , // 3 - ...
Type()} // Elems - Call the Elem:th Type() constructor
In addition, what I'd also like is that each constructor call should be able to take an arbitrary number of arguments.
A concrete example would be to automate the writing of the following:
std::array<std::shared_ptr<int>, 4> array_{std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>()}
I.e., provided that I know Type and Elem, I'd like to automate the process of creating the brace-enclosed initializer list and in the process call Type:s constructor.
Any ideas?
Update, the real problem I'd like to solve is the following:
template <typename Type, unsigned int Size>
class Storage {
public:
Storage(std::initializer_list<Type> initializer) : array_{initializer} {}
private:
std::array<Type, Size> array_;
};
void foo(){
Storage<std::shared_ptr<int>, 100> storage(...);
// or perhaps
auto storage = std::make_shared<Storage<std::shared_ptr<int>, 100>>(here be an initializer list containing calls to 100 std::make_shared<int>());
}
Like this:
#include <array>
#include <memory>
#include <utility>
template <std::size_t ...I>
std::array<std::shared_ptr<int>, sizeof...(I)> foo(std::index_sequence<I...>)
{
return {(void(I), std::make_shared<int>())...};
}
std::array<std::shared_ptr<int>, 4> array_ = foo(std::make_index_sequence<4>());
Guaranteed copy elision from C++17 ensures that the array is constructed in place, and no extra moves happen.
The return statement expands to {(void(0), std::make_shared<int>()), (void(1), std::make_shared<int>())...}. void(...) is not strictly necessary, but Clang emits a warning otherwise.
But if it was my code, I'd write a more generic helper instead:
#include <utility>
template <typename R, typename N, typename F, N ...I>
[[nodiscard]] R GenerateForEach(std::integer_sequence<N, I...>, F &&func)
{
return {(void(I), func(std::integral_constant<N, I>{}))...};
}
template <typename R, auto N, typename F>
[[nodiscard]] R Generate(F &&func)
{
return (GenerateForEach<R, decltype(N)>)(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
}
Then:
auto array_ = Generate<std::array<std::shared_ptr<int>, 4>, 4>([](auto){return std::make_shared<int>();});
While the lambda discards the index in this case, it often ends up being useful, especially given that in [](auto index){...}, index.value is constexpr.
I'm working with a struct that takes a generic function and a generic STL container, but i want to make a type check in the constructor in order to raise an error if the return type of the function is different from the constructor type: is it possible to do something like this without changing the template?
template<class Function, class Container>
struct task{
Function f;
Container& c;
task(Function func, Container& cont):f(func), c(cont){
//error if mismatch between container type and function return type
}
};
int multiply(int x){ return x*10; }
int main(){
vector<int> v;
int c=10;
auto stateless = [](float x){ return x*10;};
auto stateful = [&c](int x){ return x*c;};
task t(multiply, v); //SAME TYPE: OKAY!
task tt(stateless, v); //TYPE MISMATCH: ERROR!
return 0;
}
thank you for your help
Not sure to understand completely but... if the "generic funcion" isn't a generic-lambda or a template operator() in a class/struct... you tagged C++17 so you can use deduction guides so you can deduce the type returned from the function using std::function's deduction guides.
Something as
decltype(std::function{std::declval<Function>()})::result_type
For the value type of the container is usually available the value_type type.
So, defining a couple of using types inside the body of the struct, you can write
template <typename F, typename C>
struct task
{
using rtype = typename decltype(std::function{std::declval<F>()})::result_type;
using vtype = typename C::value_type;
// ...
task (F func, C & cont) : f{func}, c{cont}
{ static_assert( std::is_same<rtype, vtype>{} );}
};
But observe that the static_assert() inside the constructor use only elements that aren't specific of the constructor.
This way, if you have to develop (by example) ten constructors, you have to write ten times the same static_assert() inside the ten constructors bodies.
I suggest to place the static_assert() inside the body of the struct so you have to write it only one time.
I mean
template <typename F, typename C>
struct task
{
using rtype = typename decltype(std::function{std::declval<F>()})::result_type;
using vtype = typename C::value_type;
static_assert( std::is_same<rtype, vtype>{} );
// ...
};
The following is a full compiling example
#include <vector>
#include <functional>
template <typename F, typename C>
struct task
{
using rtype = typename decltype(std::function{std::declval<F>()})::result_type;
using vtype = typename C::value_type;
static_assert( std::is_same<rtype, vtype>{} );
F f;
C & c;
task (F func, C & cont) : f{func}, c{cont}
{ }
};
int multiply (int x)
{ return x*10; }
int main ()
{
std::vector<int> v;
int c=10;
auto stateless = [](float x){ return x*10;};
auto stateful = [&c](int x){ return x*c;};
task t1(multiply, v); // compile
task t2(stateful, v); // compile
task t3(stateless, v); // compilation error
}
But remember: this function doen't works with generic-lambdas.
In that case I don't know how to solve the problem and I suppose isn't solvable at all without knowing the type of the input parameters.
You can use static_assert with std::is_same to check type equality at compile time.
If your lambda function always takes no parameters, you can use decltype(f())
to get the function return type, else you will need
std::result_of / std::invoke_result or a function traits implementation.
#include <type_traits>
template<class Function, class Container>
struct task{
Function f;
Container& c;
task(Function func, Container& cont):f(func), c(cont){
static_assert(
std::is_same<
decltype(f()), // type of function return value
typename Container::value_type // type of values stored in container
>::value,
"incompatible function" // error message
);
}
};
I see no way to go ahead without using any kind of helper template to determine the parameter list here!
So the following solution is still based on Is it possible to figure out the parameter type and return type of a lambda?
For having function pointers and callable classes like lambdas, it only needs an specialized template instance.
template <typename CLASS>
struct function_traits_impl
: public function_traits_impl<decltype(&CLASS::operator())>
{};
template <typename CLASS, typename RET, typename... ARGS>
struct function_traits_impl< RET(CLASS::*)(ARGS...) const>
{
using args_type = std::tuple<ARGS...>;
using ret_type = RET;
};
template <typename CALLABLE > struct function_traits: public function_traits_impl< CALLABLE >{};
template< typename RET, typename... ARGS >
struct function_traits< RET(*)(ARGS...) >
{
using args_type = std::tuple<ARGS...>;
using ret_type = RET;
};
template < typename CLASS, typename CONTAINER, typename RET, typename ... ARGS> struct task;
template< typename CLASS, typename CONTAINER, typename RET, typename ... ARGS >
struct task< CLASS, CONTAINER, RET, std::tuple<ARGS...> >
{
using FUNC = std::function< RET(ARGS...)>;
FUNC func;
CONTAINER cont;
task( FUNC _func, CONTAINER& _cont): func{_func}, cont{_cont}
{
static_assert(
std::is_same<
//decltype( func( std::declval<PARMS>()...) ), // but is already known from given template parms!
RET,
typename CONTAINER::value_type
>::value,
"wrong return type, did not match with container type"
);
}
};
template <typename FUNC, typename CONTAINER >
task(FUNC, CONTAINER) -> task< FUNC, CONTAINER, typename function_traits<FUNC>::ret_type, typename function_traits<FUNC>::args_type>;
int Any( int ) { return 0; }
float WrongAny( int, int ) { return 1.1; }
int main()
{
std::vector<int> v;
//task t1{ [](int, int)->float { return 0; } , v}; // fails with assert as expected
task t2{ [](int, int)->int { return 0; } , v}; //Works!
task t3{ &Any , v}; // Works
//task t4{ &WrongAny, v }; fails as expected
}
This solution simply uses user defined deduction guide to forward the found parms from the trait which is helpful as you also use c++17.
Hint:
Generic lambdas cant be used, because if the parameters to call the lambda are unknown, how you could determine the parameters "automatically". It is quite easy to specify the parameters with the call and get the return type, but passing an generic lambda or an object with overloaded call operator needs to specify which of the functions/methods are should be used. So if you need generic lambdas or overloaded methods in class objects simply specify params manually! There can't be a trick in any language which allows you to give a set of optional calls and determine automatically which call should be used if no other information is available. As said: If params for the call are present, simply use them!
Remark:
If you use this solution, you only get a single template instance for all calls with same parameter set to the function call which may save some memory ;) But it uses a std::function to store teh callable which takes some runtime... You have now two solutions which differs in the results but both are usable ;)
I have a tuple of const references std::tuple<const Matrix&, ...> from which I construct a tuple of values std::tuple<Matrix, ...>. For any size of tuple greater than 1, this works fine: (online example: https://godbolt.org/g/24E8tU)
#include <tuple>
struct Matrix {
Matrix() = default;
Matrix(Matrix const&) = default;
template <typename T>
explicit Matrix(T const&) {
// in reality, this comes from Eigen, and there is real work
// being done here. this is just to demonstrate that the code
// below fails
static_assert(std::is_same<T, int>::value, "!");
}
};
void works() {
Matrix m1, m2;
std::tuple<const Matrix &, const Matrix &> tuple_of_ref{m1, m2};
std::tuple<Matrix, Matrix> t{tuple_of_ref};
}
However, for a tuple of size 1, this code fails to compile:
void fails() {
Matrix m;
std::tuple<const Matrix &> tuple_of_ref{m};
// Tries and fails to instantiate Matrix(std::tuple<const Matrix &>)
std::tuple<Matrix> t{tuple_of_ref};
}
Note the Matrix class has a templated constructor which accepts std::tuple.
template<typename T>
explicit Matrix(const T& x)
I don't want to use this constructor, and I can't change it since it's third-party code.
I think my works() example properly calls the constructor listed as #4 on cppreference:
template< class... UTypes >
tuple( const tuple<UTypes...>& other );
4) Converting copy-constructor. For all i in sizeof...(UTypes), initializes ith element of the tuple with std::get<i>(other).
The fails() example tries to use this constructor, presumably #3, which I don't want:
template< class... UTypes >
explicit tuple( UTypes&&... args );
3) Converting constructor. Initializes each element of the tuple with the corresponding value in std::forward<Utypes>(args).
How can I make sure tuple's constructor #4 is used for both cases? My real use case is inside a variadic template so I don't know the size of the tuple in advance.
Yeah, so... this is the problem:
template<typename T>
explicit Matrix(const T& x)
That is a really unfriendly constructor - because it's lying. Matrix isn't actually constructible from anything, just some specific things - but there's no way to externally detect what those things are.
When considering what how to construct a tuple<Matrix> from a tuple<Matrix const&>, we have lots of choices, but actually only two are viable:
// #2, with Types... = {Matrix}
tuple(Matrix const&);
// #3, with UTypes = {tuple<Matrix const&>&}
tuple(tuple<Matrix const&>&);
Both end up trying to construct a Matrix from a tuple<Matrix const&>, which doesn't work and you're stuck.
Now, you might think that #4 was your salvation here - generating a constructor that is:
tuple(tuple<Matrix const&> const& );
And constructing its underlying Matrix from the tuple argument's underlying Matrix. That is, using the converting copy constructor. It seems like the problem is that this constructor works but that #3 is preferred for whatever reason (i.e. that it takes a less cv-qualified reference) and that the solution is to try to fiddle with the arguments so that #4 is preferred (i.e. by using as_const() on the argument).
But that constructor isn't less preferred... it's actually not viable here because the restriction on that constructor is (from LWG 2549):
either sizeof...(Types) != 1, or (when Types... expands to T and UTypes... expands to U) is_convertible_v<const tuple<U>&, T>, is_constructible_v<T, const tuple<U>&>, and is_same_v<T, U> are all false.
But we do have sizeof..(Types) == 1 and those things are not all false (in particular, the second one is true - which is the source of all your problems to begin with), so #4 is simply not a candidate and there isn't really a neat trick to just make it one.
So, how to fix it? The best thing by far to do would to be fix Matrix. I realize that probably isn't likely, but it has to be said.
You could wrap Matrix in something that actually adds constraints to its constructor to avoid this problem. Since you're already copying it into a tuple, that gives you the opportunity to do something even as simple as:
template <typename T>
struct only_copyable {
only_copyable(only_copyable const& ) = default;
only_copyable(T const& t) : t(t) { }
template <typename U> only_copyable(U const& ) = delete;
T t;
};
but you probably want something little more realistic than this. Also your type could just inherit from Matrix and just fiddle with its constructors for sanity's sake.
Or, when dealing specifically with tuples of size 1, you could avoid using the tuple constructor and just default construct/assign. Or explicitly call get<0> or things of that sort.
Or, you could just avoid tuples of size 1 entirely. Which is a weirdly specific thing to do, but maybe that's enough (or you could wrap tuple in such a way that my_tuple<A, B, C...> is tuple<A,B,C...> but my_tuple<A> is really tuple<A, monostate>).
But really... fixing the Matrix constructor seems just super worthwhile.
Not exactly what you asked but... what about passing through a intermediate template function tplHelper() that, in the more generic case, simply return the value received
template <typename T>
T tplHelper (T const & tpl)
{ return tpl; }
but in case of a std::tuple with a single type return the contained value ?
template <typename T>
T tplHelper (std::tuple<T> const & tpl)
{ return std::get<0>(tpl); }
If you create t passing through tplHelper()
std::tuple<Matrix, Matrix> t{ tplHelper(tuple_of_ref) };
// ...
std::tuple<Matrix> t{ tplHelper(tuple_of_ref) };
when you have two or mote types, you continue to call the copy constructor of std::tuple, but when you call it with a tuple with a single matrix, you avoid the template Matrix constructor and call the copy Matrix constructor.
The following is a full working example
#include <tuple>
struct Matrix
{
Matrix ()
{ }
template <typename T>
explicit Matrix (const T &)
{
// This constructor fails to compile when T is std::tuple<...>
// and I don't want to use it at all
static_assert(sizeof(T) == 0, "!");
}
};
template <typename T>
T tplHelper (T const & tpl)
{ return tpl; }
template <typename T>
T tplHelper (std::tuple<T> const & tpl)
{ return std::get<0>(tpl); }
void m2 ()
{
Matrix m1, m2;
std::tuple<const Matrix &, const Matrix &> tuple_of_ref{m1, m2};
std::tuple<Matrix, Matrix> t{ tplHelper(tuple_of_ref) };
}
void m1 ()
{
Matrix m;
std::tuple<const Matrix &> tuple_of_ref{m};
// now compile!
std::tuple<Matrix> t{ tplHelper(tuple_of_ref) };
}
int main ()
{
m2();
m1();
}
I couldn't think of a good solution to the problem without effectively reimplementing the tuple constructor you wanted to be invoked:
struct TupleFromTuple{};
template<class... T, class... U>
struct TupleFromTuple<std::tuple<T...>, std::tuple<U...>>
{
static_assert(sizeof...(T) == sizeof...(U), "Tuples should be the same size");
using to_t = std::tuple<T...>;
using from_t = std::tuple<U...>;
static to_t Apply(from_t& tup)
{
return ApplyImpl(tup, std::index_sequence_for<T...>{});
}
private:
template<size_t... I>
static to_t ApplyImpl(from_t& tup, std::index_sequence<I...>){
return {std::get<I>(tup)...};
}
};
Demo
Uses some light C++14, but nothing that you cannot implement in C++11
Effectively we use index sequences to call std::get ourselves.
Given some garbage implementation of Matrix like so:
struct Matrix
{
Matrix() = default;
template<class T>
explicit Matrix(const T& foo){foo.fail();}
};
Your fails test now passes:
void fails() {
Matrix m;
std::tuple<const Matrix &> tuple_of_ref{m};
auto t = TupleFromTuple<std::tuple<Matrix>, decltype(tuple_of_ref)>::Apply(tuple_of_ref);
}
I'd circumvent this issue by calling std::get on the "source" tuple:
Thing thing;
std::tuple<Thing const &> get_source{thing};
std::tuple<Thing> get_target{std::get<0>(get_source)};
This avoids calling the explicit constructor and instead calls the copy constructor.
In order to generalize this for tuples of any length you can make use of std::integer_sequence and what builds upon it and wrap this all up in a function:
template<typename T>
using no_ref_cv = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template<typename... T, std::size_t... Idx>
auto MakeTupleWithCopies_impl(std::tuple<T...> const & source, std::index_sequence<Idx...>) {
return std::tuple<no_ref_cv<T>...>{std::get<Idx>(source)...};
}
template<typename... T>
auto MakeTupleWithCopies(std::tuple<T...> const & source) {
return MakeTupleWithCopies_impl(source, std::index_sequence_for<T...>{});
}
Stuck with C++11?
std::integer_sequence and it's friends can be written in C++11, too (not a full replacement, misses member function for example and probably breaks with signed integer types):
template<typename T, T...>
struct integer_sequence {};
template<std::size_t... Ints>
using index_sequence = integer_sequence<std::size_t, Ints...>;
template<typename T, T... t>
integer_sequence<T, t..., sizeof...(t)> inc(integer_sequence<T, t...>) {
return {};
}
template<typename T, T N, std::size_t Count>
struct make_integer_sequence_help {
using type = decltype(inc(typename make_integer_sequence_help<T,N,Count - 1>::type{}));
};
template<typename T, T N>
struct make_integer_sequence_help<T, N, 0> {
using type = integer_sequence<T>;
};
template<class T, T N>
using make_integer_sequence = typename make_integer_sequence_help<T,N, N>::type;
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template<class... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
Then you only need to change the auto return type specifications of the two functions to std::tuple<no_ref_cv<T>...>.
I am trying to build a Tuple class that can be accessed like an Array. I could probably turn things into (void *) but that would defeat the purpose of the templates since I'm trying to get type-safety.
I'm compiling using VS2010 pro. My current non-working solution produces the following error.
Error: 'Item &MyList::operator ' : could not deduce template argument for 'N'.
#include <tuple>
#include <stdio.h>
template <int size, typename Ty0,
typename Ty1=std::tr1::_Nil, typename Ty2=std::tr1::_Nil, typename Ty3=std::tr1::_Nil,
typename Ty4=std::tr1::_Nil, typename Ty5=std::tr1::_Nil, typename Ty6=std::tr1::_Nil,
typename Ty7=std::tr1::_Nil, typename Ty8=std::tr1::_Nil, typename Ty9=std::tr1::_Nil>
struct MyList {
std::tuple<Ty0, Ty1, Ty2, Ty3, Ty4, Ty5, Ty6, Ty7, Ty8, Ty9> items;
template <int N, typename Ty>
Ty &operator[](int N) {
auto &var = std::get<N>(items);
return var;
}
};
void main() {
MyList<2, int, double> list;
auto var = list[0];
}
Potential Solutions: (edit)
Variadic templates with homogeneous data
Using constexpr C++11
It depends what you want to index the tuple with. If you're using a runtime integer then clearly you can't attain type safety; there's no way for the compiler to know what type to return (other in the case where the tuple is homogeneous, for which see above).
If on the other hand you're just after the syntax of subscripting, you can do this using indexing objects with appropriate types, e.g. (for exposition) the ready-made std::placeholders:
template<typename T>
typename std::tuple_element<std::is_placeholder<T>::value,
std::tuple<Ty0, Ty1, Ty2, Ty3, Ty4, Ty5, Ty6, Ty7, Ty8, Ty9>>::type &
operator[](T) { return std::get<std::is_placeholder<T>::value>(items); }
Usage:
using namespace std::placeholders;
auto var = list[_1];
I'm interested in building an uninitialized_vector container, which will be semantically identical to std::vector with the caveat that new elements which otherwise would be created with a no-argument constructor will instead be created without initialization. I'm primarily interested in avoiding initializing POD to 0. As far as I can tell, there's no way to accomplish this by combining std::vector with a special kind of allocator.
I'd like to build my container in the same vein as std::stack, which adapts a user-provided container (in my case, std::vector). In other words, I'd like to avoid reimplementing the entirety of std::vector and instead provide a "facade" around it.
Is there a simple way to control default construction from the "outside" of std::vector?
Here's the solution I arrived at, which was inspired Kerrek's answer:
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <cassert>
// uninitialized_allocator adapts a given base allocator
// uninitialized_allocator's behavior is equivalent to the base
// except for its no-argument construct function, which is a no-op
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_allocator
: BaseAllocator::template rebind<T>::other
{
typedef typename BaseAllocator::template rebind<T>::other super_t;
template<typename U>
struct rebind
{
typedef uninitialized_allocator<U, BaseAllocator> other;
};
// XXX for testing purposes
typename super_t::pointer allocate(typename super_t::size_type n)
{
auto result = super_t::allocate(n);
// fill result with 13 so we can check afterwards that
// the result was not default-constructed
std::fill(result, result + n, 13);
return result;
}
// catch default-construction
void construct(T *p)
{
// no-op
}
// forward everything else with at least one argument to the base
template<typename Arg1, typename... Args>
void construct(T* p, Arg1 &&arg1, Args&&... args)
{
super_t::construct(p, std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
};
namespace std
{
// XXX specialize allocator_traits
// this shouldn't be necessary, but clang++ 2.7 + libc++ has trouble
// recognizing that uninitialized_allocator<T> has a well-formed
// construct function
template<typename T>
struct allocator_traits<uninitialized_allocator<T> >
: std::allocator_traits<std::allocator<T>>
{
typedef uninitialized_allocator<T> allocator_type;
// for testing purposes, forward allocate through
static typename allocator_type::pointer allocate(allocator_type &a, typename allocator_type::size_type n)
{
return a.allocate(n);
}
template<typename... Args>
static void construct(allocator_type &a, T* ptr, Args&&... args)
{
a.construct(ptr, std::forward<Args>(args)...);
};
};
}
// uninitialized_vector is implemented by adapting an allocator and
// inheriting from std::vector
// a template alias would be another possiblity
// XXX does not compile with clang++ 2.9
//template<typename T, typename BaseAllocator>
//using uninitialized_vector = std::vector<T, uninitialized_allocator<T,BaseAllocator>>;
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_vector
: std::vector<T, uninitialized_allocator<T,BaseAllocator>>
{};
int main()
{
uninitialized_vector<int> vec;
vec.resize(10);
// everything should be 13
assert(std::count(vec.begin(), vec.end(), 13) == vec.size());
// copy construction should be preserved
vec.push_back(7);
assert(7 == vec.back());
return 0;
}
This solution will work depending on how closely a particular vendor's compiler & STL's std::vector implementation conforms to c++11.
Instead of using a wrapper around the container, consider using a wrapper around the element type:
template <typename T>
struct uninitialized
{
uninitialized() { }
T value;
};
I think the problem boils down to the type of initialization that the container performs on elements. Compare:
T * p1 = new T; // default-initalization
T * p2 = new T(); // value-initialization
The problem with the standard containers is that they take the default argument to be value initialized, as in resize(size_t, T = T()). This means that there's no elegant way to avoid value-initialization or copying. (Similarly for the constructor.)
Even using the standard allocators doesn't work, because their central construct() function takes an argument that becomes value-initialized. What you would rather need is a construct() that uses default-initialization:
template <typename T>
void definit_construct(void * addr)
{
new (addr) T; // default-initialization
}
Such a thing wouldn't be a conforming standard allocator any more, but you could build your own container around that idea.
I don't believe this is possible by wrapping a vector (that works with every type), unless you resize the vector on every add and remove operation.
If you could give up wrapping STL containers, you could do this by keeping an array of char on the heap and using placement new for each of the objects you want to construct. This way you could control exactly when the constructors and destructors of objects were called, one by one.