Date: Fri, 27 Jun 2025 00:13:40 +0200
Hi,
Motivation:
std::initializer_list is known to have two issues:
1) it does not support move only types,
2) constructor that takes std::initializer_list breaks consistency between
direct- and list-initialization.
Proposed solutions:
For problem 1) for all STL containers introduce additional constructor
overloads as below
#include <cstddef>
constexpr struct from_range_t{} from_range;
template <typename T>
struct vector
{
template <std::size_t N>
vector(from_range_t, T (&&arr)[N]) {}
template <std::size_t N>
vector(from_range_t, const T (&arr)[N]) {}
};
template <typename T, std::size_t N>
vector(const T (&)[N]) -> vector<T>;
int main()
{
// today
using Arr = int[];
vector<int> v1 = {from_range, Arr{1, 2u, 3}};
// proposed
vector<int> v2 = {from_range, {1, 2u, 3}};
}
https://godbolt.org/z/doMavhhvd
Alternatively we could change the core language so that when default
template argument is T[], then template parameter is deduced as array of
known size:
#include <cstddef>
#include <type_traits>
constexpr struct from_range_t{} from_range;
template <typename T>
struct vector
{
template <typename Range = T[]>
vector(from_range_t, Range&& r)
{
// Range is int[] today
static_assert(std::is_same_v<Range, int[3]>);
}
};
template <typename T, std::size_t N>
vector(const T (&)[N]) -> vector<T>;
int main()
{
// today
using Arr = int[];
vector<int> v1 = {from_range, Arr{1, 2u, 3}};
// proposed
vector<int> v2 = {from_range, {1, 2u, 3}};
}
For problem 2) deprecate the behaviour where list-initialization invokes a
constructor with a std::initializer_list parameter, so people migrate to
new constructors from 1)
When std::initializer_list will be eventually removed we will get some more
consistency in initialization:
- T(a, b, c) and T{a, b, c} will always choose the same constructors.
Regards,
Maciej Cencora
Motivation:
std::initializer_list is known to have two issues:
1) it does not support move only types,
2) constructor that takes std::initializer_list breaks consistency between
direct- and list-initialization.
Proposed solutions:
For problem 1) for all STL containers introduce additional constructor
overloads as below
#include <cstddef>
constexpr struct from_range_t{} from_range;
template <typename T>
struct vector
{
template <std::size_t N>
vector(from_range_t, T (&&arr)[N]) {}
template <std::size_t N>
vector(from_range_t, const T (&arr)[N]) {}
};
template <typename T, std::size_t N>
vector(const T (&)[N]) -> vector<T>;
int main()
{
// today
using Arr = int[];
vector<int> v1 = {from_range, Arr{1, 2u, 3}};
// proposed
vector<int> v2 = {from_range, {1, 2u, 3}};
}
https://godbolt.org/z/doMavhhvd
Alternatively we could change the core language so that when default
template argument is T[], then template parameter is deduced as array of
known size:
#include <cstddef>
#include <type_traits>
constexpr struct from_range_t{} from_range;
template <typename T>
struct vector
{
template <typename Range = T[]>
vector(from_range_t, Range&& r)
{
// Range is int[] today
static_assert(std::is_same_v<Range, int[3]>);
}
};
template <typename T, std::size_t N>
vector(const T (&)[N]) -> vector<T>;
int main()
{
// today
using Arr = int[];
vector<int> v1 = {from_range, Arr{1, 2u, 3}};
// proposed
vector<int> v2 = {from_range, {1, 2u, 3}};
}
For problem 2) deprecate the behaviour where list-initialization invokes a
constructor with a std::initializer_list parameter, so people migrate to
new constructors from 1)
When std::initializer_list will be eventually removed we will get some more
consistency in initialization:
- T(a, b, c) and T{a, b, c} will always choose the same constructors.
Regards,
Maciej Cencora
Received on 2025-06-26 22:13:56