OpenSiv3D
OpenSiv3D copied to clipboard
Array, Grid の推論補助を追加
#1307 の修正と、機能追加です。
追加される機能
- 新たに以下のコンストラクタで CTAD が効くようになります
Array(size_type count, const value_type& value, const Allocator& alloc = Allocator{})Array(size_type size, Arg::generator_<Fty> generator)Array(size_type size, Arg::indexedGenerator_<Fty> indexedGenerator)Grid(size_type w, size_type h, const value_type& value)Grid(Size size, const value_type& value)Grid(size_type w, size_type h, Arg::generator_<Fty> generator)Grid(Size size, Arg::generator_<Fty> generator)Grid(size_type w, size_type h, Arg::indexedGenerator_<Fty> indexedGenerator)Grid(Size size, Arg::indexedGenerator_<Fty> indexedGenerator)
- Issue では
const value_type&を引数に取るコンストラクタについて問題提起しましたが、この問題を解決するにあたってArg::generatorやArg::indexedGeneratorを考慮する必要があったので、一緒にArg::generatorやArg::indexedGeneratorを取るコンストラクタでも CTAD が効くようにしました - この PR で
Grid g(2, 2, Array<int, Allocator<int>>{})のようなコードが有効になってしまいます- コンストラクタ
Grid(size_type w, size_type h, const Array<value_type>& data)の引数dataはGrid::allocator_typeにかかわらずデフォルトのアロケータを使用するArrayであり、Array<int, Allocator<int>>などの値は渡せません - 変更前はエラーでしたが、変更後は以下のように CTAD が非直感的に働く可能性があります
-
Array<int> a1{ 3, 1, 4, 1 }; Array<int, Allocator<int>> a2{ 3, 1, 4, 1 }; Grid g1(2, 2, a1); // Grid<int> に推論される Grid g2(2, 2, a2); // Grid<Array<int, Allocator<int>>> に推論される(!)
- コンストラクタ
実装
Array.hpp,Grid.hppに推論補助を追加しました- 追加した推論補助
Array(typename Array<Type, Allocator>::size_type, const Type&, const Allocator& = Allocator{}) -> Array<Type, Allocator>には以下のような問題があったため、std::is_same_v<typename Allocator::value_type, Type>でこの推論補助を制約しています-
std::list<int> list{ 3, 1, 4, 1 }; Allocator<int> alloc; Array a(list.begin(), list.end(), alloc); // Array<std::list<int>::iterator, Allocator<int>> に推論され、コンパイルエラー
-
- 追加した推論補助
Array(typename Array<Type, Allocator>::size_type, const Type&, const Allocator& = Allocator{}) -> Array<Type, Allocator>および対応するGridの推論補助には以下のような問題があったため、not detail::IsNamedParameter_v<Type>でこれらの推論補助を制約しています-
Array a(3, Arg::generator = [] { return 42; }); // Array<Arg::generator_<...>> に推論される Grid g1(2, 2, Arg::generator = [] { return 42; }); // Grid<Arg::generator_<...>> に推論される Grid g2(Size{ 2, 2 }, Arg::generator = [] { return 42; }); // Grid<Arg::generator_<...>> に推論される detail::IsNamedParameter_vを定義し、~~面倒だったので~~Arg::generator,Arg::indexedGeneratorだけでなくすべてのNamedParameterを弾いていますdetail::IsNamedParameter_vの定義は少し変なところに置いており、適切ではないかもしれません
-
テストコード
# include <Siv3D.hpp> // Siv3D v0.6.16
struct ArrayIsh
{
const Array<int, Allocator<int>>& asArray() const;
};
static_assert(requires (
Array<int, Allocator<int>> a,
std::vector<int, Allocator<int>> v,
Allocator<int> alloc)
{
{ Array(a) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(std::move(a)) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(v) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(std::move(v)) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(3, 42) } -> std::same_as<Array<int>>;
{ Array(3, 42, alloc) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(a.begin(), a.end()) } -> std::same_as<Array<int>>;
{ Array(a.begin(), a.end(), alloc) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(a) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(a, alloc) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(std::move(a)) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(std::move(a), alloc) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(v) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(v, alloc) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(std::move(v)) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(std::move(v), alloc) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array({ 42, 42, 42 }) } -> std::same_as<Array<int>>;
{ Array({ 42, 42, 42 }, alloc) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(ArrayIsh{}) } -> std::same_as<Array<int, Allocator<int>>>;
{ Array(3, Arg::generator = [] { return 42; }) } -> std::same_as<Array<int>>;
{ Array(3, Arg::indexedGenerator = [](size_t) { return 42; }) } -> std::same_as<Array<int>>;
});
static_assert(requires (
Grid<int, Allocator<int>> g,
Array<int> a,
Allocator<int> alloc)
{
{ Grid(g) } -> std::same_as<Grid<int, Allocator<int>>>;
{ Grid(std::move(g)) } -> std::same_as<Grid<int, Allocator<int>>>;
{ Grid(2, 2, 42) } -> std::same_as<Grid<int>>;
{ Grid(Size{ 2, 2 }, 42) } -> std::same_as<Grid<int>>;
{ Grid(2, 2, a) } -> std::same_as<Grid<int>>;
{ Grid(2, 2, std::move(a)) } -> std::same_as<Grid<int>>;
{ Grid(Size{ 2, 2 }, a) } -> std::same_as<Grid<int>>;
{ Grid(Size{ 2, 2 }, std::move(a)) } -> std::same_as<Grid<int>>;
{ Grid({ { 42, 42 }, { 42, 42 } }) } -> std::same_as<Grid<int>>;
{ Grid(2, 2, Arg::generator = [] { return 42; }) } -> std::same_as<Grid<int>>;
{ Grid(Size{ 2, 2 }, Arg::generator = [] { return 42; }) } -> std::same_as<Grid<int>>;
{ Grid(2, 2, Arg::indexedGenerator = [](Point) { return 42; }) } -> std::same_as<Grid<int>>;
{ Grid(Size{ 2, 2 }, Arg::indexedGenerator = [](Point) { return 42; }) } -> std::same_as<Grid<int>>;
});
void Main()
{
while (System::Update())
{
}
}