make_unique with brace initialization - c++

https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique writes that std::make_unique can be implemented as
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
This does not work for plain structs with no constructors. Those can be brace-initialized but don't have a non-default constructor. Example:
#include <memory>
struct point { int x, z; };
int main() { std::make_unique<point>(1, 2); }
Compiling this will have the compiler complain about lack of a 2-argument constructor, and rightly so.
I wonder, is there any technical reason not to define the function in terms of brace initialization instead? As in
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
That works well enough for the scenario above. Are there any other legitimate use cases this would break?
Seeing how the general trend appears to prefer braces for initialization, I would assume making braces in that template would be the canonical choice, but the fact that the standard doesn't do it might be an indication of me missing something.

In C++20, this will compile:
std::make_unique<point>(1, 2);
due to the new rule allowing initializing aggregates from a parenthesized list of values.
In C++17, you can just do:
std::unique_ptr<point>(new point{1, 2});
That won't work with make_shared though. So you can also just create a factory (forwarding left as an exercise):
template <typename... Args>
struct braced_init {
braced_init(Args... args) : args(args...) { }
std::tuple<Args...> args;
template <typename T>
operator T() const {
return std::apply([](Args... args){
return T{args...};
}, args);
}
};
std::make_unique<point>(braced_init(1, 2));
In C++14, you'll have to implement apply and write a factory function for braced_init because there's no CTAD yet - but these are doable.
Seeing how the general trend appears to prefer braces for initialization
Citation needed. It's a charged topic - but I definitely disagree with the claim.

Some classes have different behavior with the 2 initialization styles. e.g.
std::vector<int> v1(1, 2); // 1 element with value 2
std::vector<int> v2{1, 2}; // 2 elements with value 1 & 2
There might not be enough reason to choose one prefer to another; I think the standard just choose one and state the decision explicitly.
As the workaround, you might want to implement your own make_unique version. As you have showed, it's not a hard work.

In addition to other answers, in his presentation on C++17, Alisdair Meredith gives the following implementation of make_unique:
template<typename T, typename... Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T> {
if constexpr (std::is_constructible<T, Args...>::value)
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
else
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
It uses C+17 if constexpr, but can easily be rewritten without it.
With this version you can do both
auto v = make_unique<std::vector<int>>(10, 20); // *v is a vector of 10 elements
and
auto p = make_unique<point>(10, 20); // *p is a point (10, 20)

Related

Get Last element of parameter pack in C++17 / C++20

I would like to get the last element of a parameter pack. I did it with the following code GodBolt:
template<typename... Args>
auto last(Args&&... args){
const auto& last = (args, ...);
return last;
}
But now I get the warning
left operand of comma operator has no effect
But this is exactly what I wanted to achieve... Is there a way to make it clear.
In general I like to get warnings for unused values so I don't want to disable all of them (-Wno-unused-value).
In addition I could do it with a recursive template, but a fold expression seems to be better here.
Wrapping args in any function call would remove the warning.
You could make an identity function specifically for this purpose, but you might as well use std::forward and get proper forwarding as a bonus.
template<typename... Args>
decltype(auto) last(Args&&... args){
return (std::forward<Args>(args), ...);
}
Make a tuple and get the last element:
template<typename... Args>
auto last(Args&&... args)
{
return std::get<sizeof...(Args)-1>(std::forward_as_tuple(args...));
}
Test:
int main()
{
auto&& last_element = last(1, 1.0, true);
static_assert(std::is_same_v<bool, std::remove_cvref_t<decltype(last_element)>>);
}
Demo
C++11 Friendly Demo
As suggested by HolyBlackCat the easiest way to remove this warning is to use an "identity / dummy-function" like this:
template<typename T>
constexpr inline decltype(auto) identityFkt(T&& t)
{
return std::forward<T>(t);
}
It can be used this way:
const auto& last = (identityFkt(std::forward<AParamPack>(aParamPack)), ...);
It results in the same assembly (checked # godbolt) - no overhead (with -O3).
Thank you: #HolyBlackCat
You can use another implementation (it's less efficient, but compiler should be able remove inefficiency here)
template <class T>
decltype(auto) last(T && ... t) { return t; }
template <class ... TT,class T>
decltype(auto) last(T &&,TT && ... tt) { return last( std::forward<TT>(tt)... ); }

Is it possible to define a std::array without size? [duplicate]

(Note: This question is about not having to specify the number of elements and still allow nested types to be directly initialized.)
This question discusses the uses left for a C array like int arr[20];. On his answer, #James Kanze shows one of the last strongholds of C arrays, it's unique initialization characteristics:
int arr[] = { 1, 3, 3, 7, 0, 4, 2, 0, 3, 1, 4, 1, 5, 9 };
We don't have to specify the number of elements, hooray! Now iterate over it with the C++11 functions std::begin and std::end from <iterator> (or your own variants) and you never need to even think of its size.
Now, are there any (possibly TMP) ways to achieve the same with std::array? Use of macros allowed to make it look nicer. :)
??? std_array = { "here", "be", "elements" };
Edit: Intermediate version, compiled from various answers, looks like this:
#include <array>
#include <utility>
template<class T, class... Tail, class Elem = typename std::decay<T>::type>
std::array<Elem,1+sizeof...(Tail)> make_array(T&& head, Tail&&... values)
{
return { std::forward<T>(head), std::forward<Tail>(values)... };
}
// in code
auto std_array = make_array(1,2,3,4,5);
And employs all kind of cool C++11 stuff:
Variadic Templates
sizeof...
rvalue references
perfect forwarding
std::array, of course
uniform initialization
omitting the return type with uniform initialization
type inference (auto)
And an example can be found here.
However, as #Johannes points out in the comment on #Xaade's answer, you can't initialize nested types with such a function. Example:
struct A{ int a; int b; };
// C syntax
A arr[] = { {1,2}, {3,4} };
// using std::array
??? std_array = { {1,2}, {3,4} };
Also, the number of initializers is limited to the number of function and template arguments supported by the implementation.
Best I can think of is:
template<class T, class... Tail>
auto make_array(T head, Tail... tail) -> std::array<T, 1 + sizeof...(Tail)>
{
std::array<T, 1 + sizeof...(Tail)> a = { head, tail ... };
return a;
}
auto a = make_array(1, 2, 3);
However, this requires the compiler to do NRVO, and then also skip the copy of returned value (which is also legal but not required). In practice, I would expect any C++ compiler to be able to optimize that such that it's as fast as direct initialization.
I'd expect a simple make_array.
template<typename ret, typename... T> std::array<ret, sizeof...(T)> make_array(T&&... refs) {
// return std::array<ret, sizeof...(T)>{ { std::forward<T>(refs)... } };
return { std::forward<T>(refs)... };
}
Combining a few ideas from previous posts, here's a solution that works even for nested constructions (tested in GCC4.6):
template <typename T, typename ...Args>
std::array<T, sizeof...(Args) + 1> make_array(T && t, Args &&... args)
{
static_assert(all_same<T, Args...>::value, "make_array() requires all arguments to be of the same type."); // edited in
return std::array<T, sizeof...(Args) + 1>{ std::forward<T>(t), std::forward<Args>(args)...};
}
Strangely, can cannot make the return value an rvalue reference, that would not work for nested constructions. Anyway, here's a test:
auto q = make_array(make_array(make_array(std::string("Cat1"), std::string("Dog1")), make_array(std::string("Mouse1"), std::string("Rat1"))),
make_array(make_array(std::string("Cat2"), std::string("Dog2")), make_array(std::string("Mouse2"), std::string("Rat2"))),
make_array(make_array(std::string("Cat3"), std::string("Dog3")), make_array(std::string("Mouse3"), std::string("Rat3"))),
make_array(make_array(std::string("Cat4"), std::string("Dog4")), make_array(std::string("Mouse4"), std::string("Rat4")))
);
std::cout << q << std::endl;
// produces: [[[Cat1, Dog1], [Mouse1, Rat1]], [[Cat2, Dog2], [Mouse2, Rat2]], [[Cat3, Dog3], [Mouse3, Rat3]], [[Cat4, Dog4], [Mouse4, Rat4]]]
(For the last output I'm using my pretty-printer.)
Actually, let us improve the type safety of this construction. We definitely need all types to be the same. One way is to add a static assertion, which I've edited in above. The other way is to only enable make_array when the types are the same, like so:
template <typename T, typename ...Args>
typename std::enable_if<all_same<T, Args...>::value, std::array<T, sizeof...(Args) + 1>>::type
make_array(T && t, Args &&... args)
{
return std::array<T, sizeof...(Args) + 1> { std::forward<T>(t), std::forward<Args>(args)...};
}
Either way, you will need the variadic all_same<Args...> type trait. Here it is, generalizing from std::is_same<S, T> (note that decaying is important to allow mixing of T, T&, T const & etc.):
template <typename ...Args> struct all_same { static const bool value = false; };
template <typename S, typename T, typename ...Args> struct all_same<S, T, Args...>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value && all_same<T, Args...>::value;
};
template <typename S, typename T> struct all_same<S, T>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value;
};
template <typename T> struct all_same<T> { static const bool value = true; };
Note that make_array() returns by copy-of-temporary, which the compiler (with sufficient optimisation flags!) is allowed to treat as an rvalue or otherwise optimize away, and std::array is an aggregate type, so the compiler is free to pick the best possible construction method.
Finally, note that you cannot avoid copy/move construction when make_array sets up the initializer. So std::array<Foo,2> x{Foo(1), Foo(2)}; has no copy/move, but auto x = make_array(Foo(1), Foo(2)); has two copy/moves as the arguments are forwarded to make_array. I don't think you can improve on that, because you can't pass a variadic initializer list lexically to the helper and deduce type and size -- if the preprocessor had a sizeof... function for variadic arguments, perhaps that could be done, but not within the core language.
Using trailing return syntax make_array can be further simplified
#include <array>
#include <type_traits>
#include <utility>
template <typename... T>
auto make_array(T&&... t)
-> std::array<std::common_type_t<T...>, sizeof...(t)>
{
return {std::forward<T>(t)...};
}
int main()
{
auto arr = make_array(1, 2, 3, 4, 5);
return 0;
}
Unfortunatelly for aggregate classes it requires explicit type specification
/*
struct Foo
{
int a, b;
}; */
auto arr = make_array(Foo{1, 2}, Foo{3, 4}, Foo{5, 6});
EDIT No longer relevant:
In fact this make_array implementation is listed in sizeof... operator
The code below introduces undefined behavior as per [namespace.std]/4.4
4.4 The behavior of a C++ program is undefined if it declares a deduction guide for any standard library class template.
# c++17 version
Thanks to template argument deduction for class templates proposal we can use deduction guides to get rid of make_array helper
#include <array>
namespace std
{
template <typename... T> array(T... t)
-> array<std::common_type_t<T...>, sizeof...(t)>;
}
int main()
{
std::array a{1, 2, 3, 4};
return 0;
}
Compiled with -std=c++1z flag under x86-64 gcc 7.0
I know it's been quite some time since this question was asked, but I feel the existing answers still have some shortcomings, so I'd like to propose my slightly modified version. Following are the points that I think some existing answers are missing.
1. No need to rely on RVO
Some answers mention that we need to rely on RVO to return the constructed array. That is not true; we can make use of copy-list-initialization to guarantee there will never be temporaries created. So instead of:
return std::array<Type, …>{values};
we should do:
return {{values}};
2. Make make_array a constexpr function
This allow us to create compile-time constant arrays.
3. No need to check that all arguments are of the same type
First off, if they are not, the compiler will issue a warning or error anyway because list-initialization doesn't allow narrowing. Secondly, even if we really decide to do our own static_assert thing (perhaps to provide better error message), we should still probably compare the arguments' decayed types rather than raw types. For example,
volatile int a = 0;
const int& b = 1;
int&& c = 2;
auto arr = make_array<int>(a, b, c); // Will this work?
If we are simply static_asserting that a, b, and c have the same type, then this check will fail, but that probably isn't what we'd expect. Instead, we should compare their std::decay_t<T> types (which are all ints)).
4. Deduce the array value type by decaying the forwarded arguments
This is similar to point 3. Using the same code snippet, but don't specify the value type explicitly this time:
volatile int a = 0;
const int& b = 1;
int&& c = 2;
auto arr = make_array(a, b, c); // Will this work?
We probably want to make an array<int, 3>, but the implementations in the existing answers probably all fail to do that. What we can do is, instead of returning a std::array<T, …>, return a std::array<std::decay_t<T>, …>.
There is one disadvantage about this approach: we can't return an array of cv-qualified value type any more. But most of the time, instead of something like an array<const int, …>, we would use a const array<int, …> anyway. There is a trade-off, but I think a reasonable one. The C++17 std::make_optional also takes this approach:
template< class T >
constexpr std::optional<std::decay_t<T>> make_optional( T&& value );
Taking the above points into account, a full working implementation of make_array in C++14 looks like this:
#include <array>
#include <type_traits>
#include <utility>
template<typename T, typename... Ts>
constexpr std::array<std::decay_t<T>, 1 + sizeof... (Ts)>
make_array(T&& t, Ts&&... ts)
noexcept(noexcept(std::is_nothrow_constructible<
std::array<std::decay_t<T>, 1 + sizeof... (Ts)>, T&&, Ts&&...
>::value))
{
return {{std::forward<T>(t), std::forward<Ts>(ts)...}};
}
template<typename T>
constexpr std::array<std::decay_t<T>, 0> make_array() noexcept
{
return {};
}
Usage:
constexpr auto arr = make_array(make_array(1, 2),
make_array(3, 4));
static_assert(arr[1][1] == 4, "!");
C++11 will support this manner of initialization for (most?) std containers.
(Solution by #dyp)
Note: requires C++14 (std::index_sequence). Although one could implement std::index_sequence in C++11.
#include <iostream>
// ---
#include <array>
#include <utility>
template <typename T>
using c_array = T[];
template<typename T, size_t N, size_t... Indices>
constexpr auto make_array(T (&&src)[N], std::index_sequence<Indices...>) {
return std::array<T, N>{{ std::move(src[Indices])... }};
}
template<typename T, size_t N>
constexpr auto make_array(T (&&src)[N]) {
return make_array(std::move(src), std::make_index_sequence<N>{});
}
// ---
struct Point { int x, y; };
std::ostream& operator<< (std::ostream& os, const Point& p) {
return os << "(" << p.x << "," << p.y << ")";
}
int main() {
auto xs = make_array(c_array<Point>{{1,2}, {3,4}, {5,6}, {7,8}});
for (auto&& x : xs) {
std::cout << x << std::endl;
}
return 0;
}
С++17 compact implementation.
template <typename... T>
constexpr auto array_of(T&&... t) {
return std::array{ static_cast<std::common_type_t<T...>>(t)... };
}
While this answer is directed more towards this question, that question was marked as a duplicate of this question. Hence, this answer is posted here.
A particular use that I feel hasn't been fully covered is a situation where you want to obtain a std::array of chars initialized with a rather long string literal but don't want to blow up the enclosing function. There are a couple of ways to go about this.
The following works but requires us to explicitly specify the size of the string literal. This is what we're trying to avoid:
auto const arr = std::array<char const, 12>{"some string"};
One might expect the following to produce the desired result:
auto const arr = std::array{"some string"};
No need to explicitly specify the size of the array during initialization due to template deduction. However, this wont work because arr is now of type std::array<const char*, 1>.
A neat way to go about this is to simply write a new deduction guide for std::array. But keep in mind that some other code could depend on the default behavior of the std::array deduction guide.
namespace std {
template<typename T, auto N>
array(T (&)[N]) -> array<T, N>;
}
With this deduction guide std::array{"some string"}; will be of type std::array<const char, 12>. It is now possible to initialize arr with a string literal that is defined somewhere else without having to specify its size:
namespace {
constexpr auto some_string = std::array{"some string"};
}
auto func() {
auto const arr = some_string;
// ...
}
Alright, but what if we need a modifiable buffer and we want to initialize it with a string literal without specifying its size?
A hacky solution would be to simply apply the std::remove_cv type trait to our new deduction guide. This is not recommended because this will lead to rather surprising results. String literals are of type const char[], so it's expected that our deduction guide attempts to match that.
It seems that a helper function is necessary in this case. With the use of the constexpr specifier, the following function can be executed at compile time:
#include <array>
#include <type_traits>
template<typename T, auto N>
constexpr auto make_buffer(T (&src)[N]) noexcept {
auto tmp = std::array<std::remove_cv_t<T>, N>{};
for (auto idx = decltype(N){}; idx < N; ++idx) {
tmp[idx] = src[idx];
}
return tmp;
}
Making it possible to initialize modifiable std::array-like buffers as such:
namespace {
constexpr auto some_string = make_buffer("some string");
}
auto func() {
auto buff = some_string;
// ...
}
And with C++20, the helper function can even be simplified:
#include <algorithm>
#include <array>
#include <type_traits>
template<typename T, auto N>
constexpr auto make_buffer(T (&src)[N]) noexcept {
std::array<std::remove_cv_t<T>, N> tmp;
std::copy(std::begin(src), std::end(src), std::begin(tmp));
return tmp;
}
C++20 UPDATE: Although there are some excellent answers that provide the desired functionality (such as Gabriel Garcia's answer that uses std::index_sequence), I am adding this answer because the simplest way to do this as of C++20 isn't mentioned: just use std::to_array(). Using the OP's last example of an array of structs:
struct A{ int a; int b; };
// C syntax
A arr[] = { {1,2}, {3,4} };
// using std::array
auto std_array = std::to_array<A>({ {1,2}, {3,4} });
If std::array is not a constraint and if you have Boost, then take a look at list_of(). This is not exactly like C type array initialization that you want. But close.
Create an array maker type.
It overloads operator, to generate an expression template chaining each element to the previous via references.
Add a finish free function that takes the array maker and generates an array directly from the chain of references.
The syntax should look something like this:
auto arr = finish( make_array<T>->* 1,2,3,4,5 );
It does not permit {} based construction, as only operator= does. If you are willing to use = we can get it to work:
auto arr = finish( make_array<T>= {1}={2}={3}={4}={5} );
or
auto arr = finish( make_array<T>[{1}][{2}[]{3}][{4}][{5}] );
None of these look like good solutions.
Using variardics limits you to your compiler-imposed limit on number of varargs and blocks recursive use of {} for substructures.
In the end, there really isn't a good solution.
What I do is I write my code so it consumes both T[] and std::array data agnostically -- it doesn't care which I feed it. Sometimes this means my forwarding code has to carefully turn [] arrays into std::arrays transparently.
None of the template approaches worked properly for me for arrays of structs, so I crafted this macro solution:
#define make_array(T, ...) \
(std::array<T,sizeof((T[]){ __VA_ARGS__ })/sizeof(T)> {{ __VA_ARGS__ }})
auto a = make_array(int, 1, 2, 3);
struct Foo { int x, y; };
auto b = make_array(Foo,
{ 1, 2 },
{ 3, 4 },
{ 5, 6 },
);
Note that although the macro expands its array arguments twice, the first time is inside sizeof, so any side effects in the expression will correctly happen only once.
Have fun!

perfect forwarding and order of function arguments evaluation

Is there a good way to forward arguments of a function f to a function g in a situation like
template<typename... T>
void g(T && ... x);
template<typename... T>
void f(T && ... x)
{
g(x..., x...);
}
In the next code x could be moved twice
template<typename... T>
void f(T && ... x)
{
g(std::forward<T>(x)..., std::forward<T>(x)...);
}
In the next code std::forward<T>(x)... could be evaluated before x...
template<typename... T>
void f(T && ... x)
{
g(x..., std::forward<T>(x)...);
}
std::forward doesn't move things - it creates a reference that says "it is ok to move from me". The actual moving occurs inside g, not in f where std::forward or std::move is called.
The problem of move is only one of the problems here. There is also the problem of passing the same object twice as a reference in two spots, which is generally considered quite rude!
We can fix that by creating temporary objects in f and pass those by reference, but that leads to a serious issue: references are often used to return values from a function, and we have the same variable being used twice -- we cannot return both results.
So the answer is "don't do that", because it is not in general safe. You have to know the semantics of both g and f to figure out what the correct thing to do is, and a simple forwarding type interface won't reflect the depth of knowledge required.
If you do have deep semantic understanding of what g and f are supposed to do, then the situation changes.
You can in general force the order using
using separate statements (obviously)
expressions separated by the comma operator. (Beware of overloaded operator,)
The use of brace initialization works because the order of evaluation of the arguments in a brace initializer list is the order in which they appear1. The following has well-defined evaluation order:
std::tuple<T..., T...> args {
std::forward<T>(x)...,
std::forward<T>(x)... }; // still not sane, but evaluation order defined
But it's still useless as g(...) might still move from the same reference twice. What you'd actually want for rvalue refs is not:
g(rvalue, std::move(rvalue)); // or
g(std::move(rvalue), rvalue); // or even
g(std::move(rvalue), std::move(rvalue)); // [sic]
The only sane way would be:
g(lvalue=std::move(rvalue), lvalue); // BUT: fix the evaluation order
So how do we achieve precisely that but generically?
Enter Indices?!
Let's say you have variadic g as you described:
template<typename... T>
void g(T && ... x)
{
}
Now, you can duplicate the arguments passed to f using
the index trick:
namespace detail // indices
{
template<std::size_t... Is> struct seq{};
template<std::size_t I, std::size_t... Is>
struct gen_seq : gen_seq<I-1, I-1, Is...>{};
template<std::size_t... Is>
struct gen_seq<0, Is...>{ using type = seq<Is...>; };
}
and an invoker helper function:
#include <tuple>
template<typename Tuple, std::size_t... Is>
void f_invoke_helper(Tuple const& tup, detail::seq<Is...>)
{
g(std::get<Is>(tup)..., std::get<Is>(tup)...);
}
All that's required next is to tie it all together:
template<typename... T>
void f(T && ... x)
{
f_invoke_helper(
std::make_tuple(std::forward<T>(x)...),
typename detail::gen_seq<sizeof...(T)>::type());
}
Note that if you pass rvalue-refs, it will get moved once (into the tuple) and used twice (as a lvalue) in the invoker helper:
int main()
{
std::string x = "Hello world";
int i = 42;
// no problem:
f(i, -42, std::move(x));
}
Hope this helps!
PS. As it has been aptly pointed out, it's probably a lot easier to just say
template<typename... T>
void f(T&&... x) { g(x..., x...); }
I haven't thought of a way in which the tuple idiom doesn't result in the same, except for actually moving movable arguments into the tuple.
1The semantics of T{...} are described in 12.6.1See also: how to avoid undefined execution order for the constructors when using std::make_tuple .

Avoiding default construction of elements in standard containers

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.

How to emulate C array initialization "int arr[] = { e1, e2, e3, ... }" behaviour with std::array?

(Note: This question is about not having to specify the number of elements and still allow nested types to be directly initialized.)
This question discusses the uses left for a C array like int arr[20];. On his answer, #James Kanze shows one of the last strongholds of C arrays, it's unique initialization characteristics:
int arr[] = { 1, 3, 3, 7, 0, 4, 2, 0, 3, 1, 4, 1, 5, 9 };
We don't have to specify the number of elements, hooray! Now iterate over it with the C++11 functions std::begin and std::end from <iterator> (or your own variants) and you never need to even think of its size.
Now, are there any (possibly TMP) ways to achieve the same with std::array? Use of macros allowed to make it look nicer. :)
??? std_array = { "here", "be", "elements" };
Edit: Intermediate version, compiled from various answers, looks like this:
#include <array>
#include <utility>
template<class T, class... Tail, class Elem = typename std::decay<T>::type>
std::array<Elem,1+sizeof...(Tail)> make_array(T&& head, Tail&&... values)
{
return { std::forward<T>(head), std::forward<Tail>(values)... };
}
// in code
auto std_array = make_array(1,2,3,4,5);
And employs all kind of cool C++11 stuff:
Variadic Templates
sizeof...
rvalue references
perfect forwarding
std::array, of course
uniform initialization
omitting the return type with uniform initialization
type inference (auto)
And an example can be found here.
However, as #Johannes points out in the comment on #Xaade's answer, you can't initialize nested types with such a function. Example:
struct A{ int a; int b; };
// C syntax
A arr[] = { {1,2}, {3,4} };
// using std::array
??? std_array = { {1,2}, {3,4} };
Also, the number of initializers is limited to the number of function and template arguments supported by the implementation.
Best I can think of is:
template<class T, class... Tail>
auto make_array(T head, Tail... tail) -> std::array<T, 1 + sizeof...(Tail)>
{
std::array<T, 1 + sizeof...(Tail)> a = { head, tail ... };
return a;
}
auto a = make_array(1, 2, 3);
However, this requires the compiler to do NRVO, and then also skip the copy of returned value (which is also legal but not required). In practice, I would expect any C++ compiler to be able to optimize that such that it's as fast as direct initialization.
I'd expect a simple make_array.
template<typename ret, typename... T> std::array<ret, sizeof...(T)> make_array(T&&... refs) {
// return std::array<ret, sizeof...(T)>{ { std::forward<T>(refs)... } };
return { std::forward<T>(refs)... };
}
Combining a few ideas from previous posts, here's a solution that works even for nested constructions (tested in GCC4.6):
template <typename T, typename ...Args>
std::array<T, sizeof...(Args) + 1> make_array(T && t, Args &&... args)
{
static_assert(all_same<T, Args...>::value, "make_array() requires all arguments to be of the same type."); // edited in
return std::array<T, sizeof...(Args) + 1>{ std::forward<T>(t), std::forward<Args>(args)...};
}
Strangely, can cannot make the return value an rvalue reference, that would not work for nested constructions. Anyway, here's a test:
auto q = make_array(make_array(make_array(std::string("Cat1"), std::string("Dog1")), make_array(std::string("Mouse1"), std::string("Rat1"))),
make_array(make_array(std::string("Cat2"), std::string("Dog2")), make_array(std::string("Mouse2"), std::string("Rat2"))),
make_array(make_array(std::string("Cat3"), std::string("Dog3")), make_array(std::string("Mouse3"), std::string("Rat3"))),
make_array(make_array(std::string("Cat4"), std::string("Dog4")), make_array(std::string("Mouse4"), std::string("Rat4")))
);
std::cout << q << std::endl;
// produces: [[[Cat1, Dog1], [Mouse1, Rat1]], [[Cat2, Dog2], [Mouse2, Rat2]], [[Cat3, Dog3], [Mouse3, Rat3]], [[Cat4, Dog4], [Mouse4, Rat4]]]
(For the last output I'm using my pretty-printer.)
Actually, let us improve the type safety of this construction. We definitely need all types to be the same. One way is to add a static assertion, which I've edited in above. The other way is to only enable make_array when the types are the same, like so:
template <typename T, typename ...Args>
typename std::enable_if<all_same<T, Args...>::value, std::array<T, sizeof...(Args) + 1>>::type
make_array(T && t, Args &&... args)
{
return std::array<T, sizeof...(Args) + 1> { std::forward<T>(t), std::forward<Args>(args)...};
}
Either way, you will need the variadic all_same<Args...> type trait. Here it is, generalizing from std::is_same<S, T> (note that decaying is important to allow mixing of T, T&, T const & etc.):
template <typename ...Args> struct all_same { static const bool value = false; };
template <typename S, typename T, typename ...Args> struct all_same<S, T, Args...>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value && all_same<T, Args...>::value;
};
template <typename S, typename T> struct all_same<S, T>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value;
};
template <typename T> struct all_same<T> { static const bool value = true; };
Note that make_array() returns by copy-of-temporary, which the compiler (with sufficient optimisation flags!) is allowed to treat as an rvalue or otherwise optimize away, and std::array is an aggregate type, so the compiler is free to pick the best possible construction method.
Finally, note that you cannot avoid copy/move construction when make_array sets up the initializer. So std::array<Foo,2> x{Foo(1), Foo(2)}; has no copy/move, but auto x = make_array(Foo(1), Foo(2)); has two copy/moves as the arguments are forwarded to make_array. I don't think you can improve on that, because you can't pass a variadic initializer list lexically to the helper and deduce type and size -- if the preprocessor had a sizeof... function for variadic arguments, perhaps that could be done, but not within the core language.
Using trailing return syntax make_array can be further simplified
#include <array>
#include <type_traits>
#include <utility>
template <typename... T>
auto make_array(T&&... t)
-> std::array<std::common_type_t<T...>, sizeof...(t)>
{
return {std::forward<T>(t)...};
}
int main()
{
auto arr = make_array(1, 2, 3, 4, 5);
return 0;
}
Unfortunatelly for aggregate classes it requires explicit type specification
/*
struct Foo
{
int a, b;
}; */
auto arr = make_array(Foo{1, 2}, Foo{3, 4}, Foo{5, 6});
EDIT No longer relevant:
In fact this make_array implementation is listed in sizeof... operator
The code below introduces undefined behavior as per [namespace.std]/4.4
4.4 The behavior of a C++ program is undefined if it declares a deduction guide for any standard library class template.
# c++17 version
Thanks to template argument deduction for class templates proposal we can use deduction guides to get rid of make_array helper
#include <array>
namespace std
{
template <typename... T> array(T... t)
-> array<std::common_type_t<T...>, sizeof...(t)>;
}
int main()
{
std::array a{1, 2, 3, 4};
return 0;
}
Compiled with -std=c++1z flag under x86-64 gcc 7.0
I know it's been quite some time since this question was asked, but I feel the existing answers still have some shortcomings, so I'd like to propose my slightly modified version. Following are the points that I think some existing answers are missing.
1. No need to rely on RVO
Some answers mention that we need to rely on RVO to return the constructed array. That is not true; we can make use of copy-list-initialization to guarantee there will never be temporaries created. So instead of:
return std::array<Type, …>{values};
we should do:
return {{values}};
2. Make make_array a constexpr function
This allow us to create compile-time constant arrays.
3. No need to check that all arguments are of the same type
First off, if they are not, the compiler will issue a warning or error anyway because list-initialization doesn't allow narrowing. Secondly, even if we really decide to do our own static_assert thing (perhaps to provide better error message), we should still probably compare the arguments' decayed types rather than raw types. For example,
volatile int a = 0;
const int& b = 1;
int&& c = 2;
auto arr = make_array<int>(a, b, c); // Will this work?
If we are simply static_asserting that a, b, and c have the same type, then this check will fail, but that probably isn't what we'd expect. Instead, we should compare their std::decay_t<T> types (which are all ints)).
4. Deduce the array value type by decaying the forwarded arguments
This is similar to point 3. Using the same code snippet, but don't specify the value type explicitly this time:
volatile int a = 0;
const int& b = 1;
int&& c = 2;
auto arr = make_array(a, b, c); // Will this work?
We probably want to make an array<int, 3>, but the implementations in the existing answers probably all fail to do that. What we can do is, instead of returning a std::array<T, …>, return a std::array<std::decay_t<T>, …>.
There is one disadvantage about this approach: we can't return an array of cv-qualified value type any more. But most of the time, instead of something like an array<const int, …>, we would use a const array<int, …> anyway. There is a trade-off, but I think a reasonable one. The C++17 std::make_optional also takes this approach:
template< class T >
constexpr std::optional<std::decay_t<T>> make_optional( T&& value );
Taking the above points into account, a full working implementation of make_array in C++14 looks like this:
#include <array>
#include <type_traits>
#include <utility>
template<typename T, typename... Ts>
constexpr std::array<std::decay_t<T>, 1 + sizeof... (Ts)>
make_array(T&& t, Ts&&... ts)
noexcept(noexcept(std::is_nothrow_constructible<
std::array<std::decay_t<T>, 1 + sizeof... (Ts)>, T&&, Ts&&...
>::value))
{
return {{std::forward<T>(t), std::forward<Ts>(ts)...}};
}
template<typename T>
constexpr std::array<std::decay_t<T>, 0> make_array() noexcept
{
return {};
}
Usage:
constexpr auto arr = make_array(make_array(1, 2),
make_array(3, 4));
static_assert(arr[1][1] == 4, "!");
C++11 will support this manner of initialization for (most?) std containers.
(Solution by #dyp)
Note: requires C++14 (std::index_sequence). Although one could implement std::index_sequence in C++11.
#include <iostream>
// ---
#include <array>
#include <utility>
template <typename T>
using c_array = T[];
template<typename T, size_t N, size_t... Indices>
constexpr auto make_array(T (&&src)[N], std::index_sequence<Indices...>) {
return std::array<T, N>{{ std::move(src[Indices])... }};
}
template<typename T, size_t N>
constexpr auto make_array(T (&&src)[N]) {
return make_array(std::move(src), std::make_index_sequence<N>{});
}
// ---
struct Point { int x, y; };
std::ostream& operator<< (std::ostream& os, const Point& p) {
return os << "(" << p.x << "," << p.y << ")";
}
int main() {
auto xs = make_array(c_array<Point>{{1,2}, {3,4}, {5,6}, {7,8}});
for (auto&& x : xs) {
std::cout << x << std::endl;
}
return 0;
}
С++17 compact implementation.
template <typename... T>
constexpr auto array_of(T&&... t) {
return std::array{ static_cast<std::common_type_t<T...>>(t)... };
}
While this answer is directed more towards this question, that question was marked as a duplicate of this question. Hence, this answer is posted here.
A particular use that I feel hasn't been fully covered is a situation where you want to obtain a std::array of chars initialized with a rather long string literal but don't want to blow up the enclosing function. There are a couple of ways to go about this.
The following works but requires us to explicitly specify the size of the string literal. This is what we're trying to avoid:
auto const arr = std::array<char const, 12>{"some string"};
One might expect the following to produce the desired result:
auto const arr = std::array{"some string"};
No need to explicitly specify the size of the array during initialization due to template deduction. However, this wont work because arr is now of type std::array<const char*, 1>.
A neat way to go about this is to simply write a new deduction guide for std::array. But keep in mind that some other code could depend on the default behavior of the std::array deduction guide.
namespace std {
template<typename T, auto N>
array(T (&)[N]) -> array<T, N>;
}
With this deduction guide std::array{"some string"}; will be of type std::array<const char, 12>. It is now possible to initialize arr with a string literal that is defined somewhere else without having to specify its size:
namespace {
constexpr auto some_string = std::array{"some string"};
}
auto func() {
auto const arr = some_string;
// ...
}
Alright, but what if we need a modifiable buffer and we want to initialize it with a string literal without specifying its size?
A hacky solution would be to simply apply the std::remove_cv type trait to our new deduction guide. This is not recommended because this will lead to rather surprising results. String literals are of type const char[], so it's expected that our deduction guide attempts to match that.
It seems that a helper function is necessary in this case. With the use of the constexpr specifier, the following function can be executed at compile time:
#include <array>
#include <type_traits>
template<typename T, auto N>
constexpr auto make_buffer(T (&src)[N]) noexcept {
auto tmp = std::array<std::remove_cv_t<T>, N>{};
for (auto idx = decltype(N){}; idx < N; ++idx) {
tmp[idx] = src[idx];
}
return tmp;
}
Making it possible to initialize modifiable std::array-like buffers as such:
namespace {
constexpr auto some_string = make_buffer("some string");
}
auto func() {
auto buff = some_string;
// ...
}
And with C++20, the helper function can even be simplified:
#include <algorithm>
#include <array>
#include <type_traits>
template<typename T, auto N>
constexpr auto make_buffer(T (&src)[N]) noexcept {
std::array<std::remove_cv_t<T>, N> tmp;
std::copy(std::begin(src), std::end(src), std::begin(tmp));
return tmp;
}
C++20 UPDATE: Although there are some excellent answers that provide the desired functionality (such as Gabriel Garcia's answer that uses std::index_sequence), I am adding this answer because the simplest way to do this as of C++20 isn't mentioned: just use std::to_array(). Using the OP's last example of an array of structs:
struct A{ int a; int b; };
// C syntax
A arr[] = { {1,2}, {3,4} };
// using std::array
auto std_array = std::to_array<A>({ {1,2}, {3,4} });
If std::array is not a constraint and if you have Boost, then take a look at list_of(). This is not exactly like C type array initialization that you want. But close.
Create an array maker type.
It overloads operator, to generate an expression template chaining each element to the previous via references.
Add a finish free function that takes the array maker and generates an array directly from the chain of references.
The syntax should look something like this:
auto arr = finish( make_array<T>->* 1,2,3,4,5 );
It does not permit {} based construction, as only operator= does. If you are willing to use = we can get it to work:
auto arr = finish( make_array<T>= {1}={2}={3}={4}={5} );
or
auto arr = finish( make_array<T>[{1}][{2}[]{3}][{4}][{5}] );
None of these look like good solutions.
Using variardics limits you to your compiler-imposed limit on number of varargs and blocks recursive use of {} for substructures.
In the end, there really isn't a good solution.
What I do is I write my code so it consumes both T[] and std::array data agnostically -- it doesn't care which I feed it. Sometimes this means my forwarding code has to carefully turn [] arrays into std::arrays transparently.
None of the template approaches worked properly for me for arrays of structs, so I crafted this macro solution:
#define make_array(T, ...) \
(std::array<T,sizeof((T[]){ __VA_ARGS__ })/sizeof(T)> {{ __VA_ARGS__ }})
auto a = make_array(int, 1, 2, 3);
struct Foo { int x, y; };
auto b = make_array(Foo,
{ 1, 2 },
{ 3, 4 },
{ 5, 6 },
);
Note that although the macro expands its array arguments twice, the first time is inside sizeof, so any side effects in the expression will correctly happen only once.
Have fun!