Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Factory function of std::array
#include <array>
#include <functional>
template <typename... T>
using common_type_t = typename std::common_type<T...>::type;
template <typename T>
using remove_cv_t = typename std::remove_cv<T>::type;
template <bool, typename T, typename... U>
struct lazy_conditional_c;
template <typename T>
struct lazy_conditional_c<true, T>
{
using type = typename T::type;
};
template <typename T, typename U>
struct lazy_conditional_c<true, T, U>
{
using type = typename T::type;
};
template <typename T, typename U>
struct lazy_conditional_c<false, T, U>
{
using type = typename U::type;
};
template <typename V, typename T, typename... U>
using if_else = lazy_conditional_c<V::value, T, U...>;
template <typename V, typename T, typename... U>
using If = typename if_else<V, T, U...>::type;
template <typename T>
struct identity_of
{
using type = T;
};
template <template <typename> class F, typename... T>
struct no_type : std::true_type {};
template <template <typename> class F, typename T1, typename... T2>
struct no_type<F, T1, T2...> :
std::integral_constant
<
bool,
not F<T1>::value and no_type<F, T2...>::value
>
{};
template <template <typename> class F, template <typename> class G>
struct composed
{
template <typename T>
using call = F<typename G<T>::type>;
};
template <typename T>
struct _is_reference_wrapper : std::false_type {};
template <typename T>
struct _is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T>
using is_reference_wrapper =
composed<_is_reference_wrapper, std::remove_cv>::call<T>;
template <typename V = void, typename... T>
constexpr auto make_array(T&&... t)
-> std::array
<
If
<
std::is_void<V>,
std::common_type<T...>,
identity_of<V>
>,
sizeof...(T)
>
{
static_assert(not std::is_void<V>() or
no_type
<
composed
<
is_reference_wrapper,
std::decay
>
::call,
T...
>(), "T shall not be reference_wrapper");
return {{ std::forward<T>(t)... }};
}
template <size_t... I>
struct _indices {};
template <size_t N, size_t... I>
struct _build_indices : _build_indices<N - 1, N - 1, I...> {};
template <size_t... I>
struct _build_indices<0, I...> : _indices<I...> {};
template <typename T, size_t N, size_t... I>
constexpr auto _to_array(T (&arr)[N], _indices<I...>)
-> std::array<remove_cv_t<T>, N>
{
return {{ arr[I]... }};
}
template <typename T, size_t N, size_t... I>
constexpr auto _to_array(T (&&arr)[N], _indices<I...>)
-> std::array<remove_cv_t<T>, N>
{
return {{ std::move(arr[I])... }};
}
template <typename T, size_t N>
constexpr auto to_array(T (&arr)[N])
-> std::array<remove_cv_t<T>, N>
{
return _to_array(arr, _build_indices<N>());
}
template <typename T, size_t N>
constexpr auto to_array(T (&&arr)[N])
-> std::array<remove_cv_t<T>, N>
{
return _to_array(std::move(arr), _build_indices<N>());
}
#include <iostream>
#include <memory>
int main()
{
auto ch = 'a';
auto const d = 65l;
auto a1 = make_array(ch, d, 0);
static_assert(std::is_same<decltype(a1)::value_type, long>(), "");
std::cout << a1[0] << std::endl;
constexpr auto a2 = to_array("abc");
static_assert(std::is_same<decltype(a2)::value_type, char>(), "");
std::cout << a2.data() << std::endl;
auto a3 = make_array("aa", "bb");
static_assert(std::is_same<decltype(a3)::value_type, char const*>(),
"fix your library");
std::cout << a3[0] << std::endl;
auto a4 = make_array<long>(2, 3U);
static_assert(std::is_same<decltype(a4)::value_type, long>(), "");
std::cout << a4[0] << std::endl;
auto a5 = make_array<short>();
static_assert(std::is_same<decltype(a5)::value_type, short>(), "");
std::cout << a5.size() << std::endl;
int a, b;
auto a6 = make_array<std::reference_wrapper<int>>(std::ref(a), b);
std::cout << a6.size() << std::endl;
auto a7 = to_array<std::pair<int, float>>(
{ { 3, .0f }, { 4, .1f }, { 4, .1e23f } });
static_assert(
std::is_same<decltype(a7)::value_type, std::pair<int, float>>(),
"");
auto a8 = to_array({ std::make_unique<int>(3) });
std::cout << *a8[0] << std::endl;
auto a9 = to_array({ 0, 2, 1, 3 });
std::cout << a9.size() << std::endl;
// ** do not compile **
//auto a7 = make_array(std::cref(""));
// ** hard error **
//char s[2][6] = { "nice", "thing" };
//auto a8 = to_array(s);
}
@boatilus

This comment has been minimized.

Copy link

commented Jan 10, 2014

Nice work! What's the current license?

@FrankHB

This comment has been minimized.

Copy link

commented Dec 26, 2014

Is these interfaces stable now? I have similar ones for years...

@lichray

This comment has been minimized.

Copy link
Owner Author

commented Feb 9, 2015

The stable one is https://gist.github.com/lichray/6034753/337240ea9777c5118ba3430c5198c2d0d4f81a03 ; the "current" one is left here for records.

@dgodfrey95

This comment has been minimized.

Copy link

commented Mar 22, 2015

I haven't studied the code yet but what does all this do differently than http://stackoverflow.com/a/6114299/701092?

@lichray

This comment has been minimized.

Copy link
Owner Author

commented Mar 24, 2015

In the stackoverflow answer, all elements are required to be implicitly convertible to the first element:

make_array(1, 1L) -> std::array<int, 2>

In this gist, common type is calculated:

make_array(1, 1L) -> std::array<long, 2>

Alternatively, you can specify the target type:

make_array<long long>(1, 1L) -> std::array<long long, 2>

Although such a syntax works in the stackoverflow version, the first argument will no longer use perfect forwarding, because it abandons the deduction behavior.

@quietdragon

This comment has been minimized.

Copy link

commented May 18, 2015

What is the license for this gist ?

@Robbepop

This comment has been minimized.

Copy link

commented Jun 14, 2015

I need this very badly in the standard! This is an extremely useful function to me! Thanks for this gist and the proposal!

@nestal

This comment has been minimized.

Copy link

commented Nov 25, 2015

I actually get there from a link in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4391.html
so it looks like it will be in a TS or C++17

@bklarson

This comment has been minimized.

Copy link

commented Dec 11, 2017

I can't get this to work with VS 2015, curious if anyone else has had luck?

struct Point { int x, y; };
auto triangle = std::make_array<Point>({3, 3}, {5, 5}, {1, 5});

c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1292): error C2440: 'return': cannot convert from 'Point [3]' to 'Point (&&)[3]'
c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1292): note: You cannot bind an lvalue to an rvalue reference
make_array.cc(125): note: see reference to function template instantiation 'Point (&&std::move<T(&)[3]>(_Ty) noexcept)[3]' being compiled 

It works fine with GCC 6.

@aCuria

This comment has been minimized.

Copy link

commented Apr 8, 2019

I love this, but am wondering if it can be improved. Would the syntax in #1 and #2 be possible?

// #1 How I would expect std::array to work
std::array<VkDescriptorPoolSize> poolSizes = (
	  VkDescriptorPoolSize{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount }
	, VkDescriptorPoolSize{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }
);

// #2 How I would expect make_array to work
auto poolSizes = make_array<VkDescriptorPoolSize>(
	  { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount }
	, { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }
);

// #3 How make_array actually works
auto poolSizes = make_array(
	  VkDescriptorPoolSize{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount }
	, VkDescriptorPoolSize{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }
);

// #4 How C/C++ works without std::array
VkDescriptorPoolSize poolSizes[] = { 
	  {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount}
	, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}
};

edit: I realized #2 is -supposed- to work, but it does not for me (VS2017)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.