Last active
August 29, 2023 16:37
-
-
Save lichray/6034753 to your computer and use it in GitHub Desktop.
Factory function of std::array
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
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.
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
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