mirror of git://gcc.gnu.org/git/gcc.git
Implement <variant>
* include/Makefile.am: Add new file std/variant. * include/Makefile.in: Generated from Makefile.am. * include/bits/enable_special_members.h: Add a tag type to allow the construction in non-default constructor. * include/bits/uses_allocator.h: Add convenience traits to detect constructibility. * include/std/variant: Implement <variant>. * testsuite/20_util/variant/compile.cc: Compile-time tests. * testsuite/20_util/variant/run.cc: Runtime tests. From-SVN: r239590
This commit is contained in:
parent
cc015f3abe
commit
197c757cb1
|
|
@ -1,3 +1,17 @@
|
|||
2016-08-18 Tim Shen <timshen@google.com>
|
||||
|
||||
Implement <variant>
|
||||
|
||||
* include/Makefile.am: Add new file std/variant.
|
||||
* include/Makefile.in: Generated from Makefile.am.
|
||||
* include/bits/enable_special_members.h: Add a tag type to allow
|
||||
the construction in non-default constructor.
|
||||
* include/bits/uses_allocator.h: Add convenience traits to
|
||||
detect constructibility.
|
||||
* include/std/variant: Implement <variant>.
|
||||
* testsuite/20_util/variant/compile.cc: Compile-time tests.
|
||||
* testsuite/20_util/variant/run.cc: Runtime tests.
|
||||
|
||||
2016-08-18 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* doc/xml/manual/test.xml (test.run.permutations): Expand section.
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ std_headers = \
|
|||
${std_srcdir}/unordered_set \
|
||||
${std_srcdir}/utility \
|
||||
${std_srcdir}/valarray \
|
||||
${std_srcdir}/variant \
|
||||
${std_srcdir}/vector
|
||||
|
||||
bits_srcdir = ${glibcxx_srcdir}/include/bits
|
||||
|
|
|
|||
|
|
@ -367,6 +367,7 @@ std_headers = \
|
|||
${std_srcdir}/unordered_set \
|
||||
${std_srcdir}/utility \
|
||||
${std_srcdir}/valarray \
|
||||
${std_srcdir}/variant \
|
||||
${std_srcdir}/vector
|
||||
|
||||
bits_srcdir = ${glibcxx_srcdir}/include/bits
|
||||
|
|
|
|||
|
|
@ -36,13 +36,33 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
struct _Enable_default_constructor_tag
|
||||
{
|
||||
explicit _Enable_default_constructor_tag() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A mixin helper to conditionally enable or disable the default
|
||||
* constructor.
|
||||
* @sa _Enable_special_members
|
||||
*/
|
||||
template<bool _Switch, typename _Tag = void>
|
||||
struct _Enable_default_constructor { };
|
||||
struct _Enable_default_constructor
|
||||
{
|
||||
constexpr _Enable_default_constructor() noexcept = default;
|
||||
constexpr _Enable_default_constructor(_Enable_default_constructor const&)
|
||||
noexcept = default;
|
||||
constexpr _Enable_default_constructor(_Enable_default_constructor&&)
|
||||
noexcept = default;
|
||||
_Enable_default_constructor&
|
||||
operator=(_Enable_default_constructor const&) noexcept = default;
|
||||
_Enable_default_constructor&
|
||||
operator=(_Enable_default_constructor&&) noexcept = default;
|
||||
|
||||
// Can be used in other ctors.
|
||||
constexpr explicit
|
||||
_Enable_default_constructor(_Enable_default_constructor_tag) { }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -86,7 +106,20 @@ template<bool _Default, bool _Destructor,
|
|||
|
||||
template<typename _Tag>
|
||||
struct _Enable_default_constructor<false, _Tag>
|
||||
{ constexpr _Enable_default_constructor() noexcept = delete; };
|
||||
{
|
||||
constexpr _Enable_default_constructor() noexcept = delete;
|
||||
constexpr _Enable_default_constructor(_Enable_default_constructor const&)
|
||||
noexcept = default;
|
||||
constexpr _Enable_default_constructor(_Enable_default_constructor&&)
|
||||
noexcept = default;
|
||||
_Enable_default_constructor&
|
||||
operator=(_Enable_default_constructor const&) noexcept = default;
|
||||
_Enable_default_constructor&
|
||||
operator=(_Enable_default_constructor&&) noexcept = default;
|
||||
|
||||
// Can be used in other ctors.
|
||||
explicit _Enable_default_constructor(_Enable_default_constructor_tag) { }
|
||||
};
|
||||
|
||||
template<typename _Tag>
|
||||
struct _Enable_destructor<false, _Tag>
|
||||
|
|
|
|||
|
|
@ -113,6 +113,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
constexpr bool uses_allocator_v = uses_allocator<_Tp, _Alloc>::value;
|
||||
#endif // C++17
|
||||
|
||||
template<template<typename...> class _Predicate,
|
||||
typename _Tp, typename _Alloc, typename... _Args>
|
||||
struct __is_uses_allocator_predicate
|
||||
: conditional<uses_allocator<_Tp, _Alloc>::value,
|
||||
__or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>,
|
||||
_Predicate<_Tp, _Args..., _Alloc>>,
|
||||
_Predicate<_Tp, _Args...>>::type { };
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
struct __is_uses_allocator_constructible
|
||||
: __is_uses_allocator_predicate<is_constructible, _Tp, _Alloc, _Args...>
|
||||
{ };
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
constexpr bool __is_uses_allocator_constructible_v =
|
||||
__is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
struct __is_nothrow_uses_allocator_constructible
|
||||
: __is_uses_allocator_predicate<is_nothrow_constructible,
|
||||
_Tp, _Alloc, _Args...>
|
||||
{ };
|
||||
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
constexpr bool __is_nothrow_uses_allocator_constructible_v =
|
||||
__is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
|
||||
|
||||
template<typename _Tp, typename... _Args>
|
||||
void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr,
|
||||
_Args&&... __args)
|
||||
{ new (__ptr) _Tp(forward<_Args>(__args)...); }
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr,
|
||||
_Args&&... __args)
|
||||
{ new (__ptr) _Tp(allocator_arg, *__a._M_a, forward<_Args>(__args)...); }
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr,
|
||||
_Args&&... __args)
|
||||
{ new (__ptr) _Tp(forward<_Args>(__args)..., *__a._M_a); }
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr,
|
||||
_Args&&... __args)
|
||||
{
|
||||
__uses_allocator_construct_impl(__use_alloc<_Tp, _Alloc, _Args...>(__a),
|
||||
__ptr, forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,405 @@
|
|||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <variant>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct AllDeleted
|
||||
{
|
||||
AllDeleted() = delete;
|
||||
AllDeleted(const AllDeleted&) = delete;
|
||||
AllDeleted(AllDeleted&&) = delete;
|
||||
AllDeleted& operator=(const AllDeleted&) = delete;
|
||||
AllDeleted& operator=(AllDeleted&&) = delete;
|
||||
};
|
||||
|
||||
struct Empty
|
||||
{
|
||||
Empty() { };
|
||||
Empty(const Empty&) { };
|
||||
Empty(Empty&&) { };
|
||||
Empty& operator=(const Empty&) { return *this; };
|
||||
Empty& operator=(Empty&&) { return *this; };
|
||||
};
|
||||
|
||||
struct DefaultNoexcept
|
||||
{
|
||||
DefaultNoexcept() noexcept = default;
|
||||
DefaultNoexcept(const DefaultNoexcept&) noexcept = default;
|
||||
DefaultNoexcept(DefaultNoexcept&&) noexcept = default;
|
||||
DefaultNoexcept& operator=(const DefaultNoexcept&) noexcept = default;
|
||||
DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default;
|
||||
};
|
||||
|
||||
void default_ctor()
|
||||
{
|
||||
static_assert(is_default_constructible_v<variant<int, string>>, "");
|
||||
static_assert(is_default_constructible_v<variant<string, string>>, "");
|
||||
static_assert(!is_default_constructible_v<variant<>>, "");
|
||||
static_assert(!is_default_constructible_v<variant<AllDeleted, string>>, "");
|
||||
static_assert(is_default_constructible_v<variant<string, AllDeleted>>, "");
|
||||
|
||||
static_assert(noexcept(variant<int>()), "");
|
||||
static_assert(!noexcept(variant<Empty>()), "");
|
||||
static_assert(noexcept(variant<DefaultNoexcept>()), "");
|
||||
}
|
||||
|
||||
void copy_ctor()
|
||||
{
|
||||
static_assert(is_copy_constructible_v<variant<int, string>>, "");
|
||||
static_assert(!is_copy_constructible_v<variant<AllDeleted, string>>, "");
|
||||
|
||||
{
|
||||
variant<int> a;
|
||||
static_assert(!noexcept(variant<int>(a)), "");
|
||||
}
|
||||
{
|
||||
variant<string> a;
|
||||
static_assert(!noexcept(variant<string>(a)), "");
|
||||
}
|
||||
{
|
||||
variant<int, string> a;
|
||||
static_assert(!noexcept(variant<int, string>(a)), "");
|
||||
}
|
||||
{
|
||||
variant<int, char> a;
|
||||
static_assert(!noexcept(variant<int, char>(a)), "");
|
||||
}
|
||||
}
|
||||
|
||||
void move_ctor()
|
||||
{
|
||||
static_assert(is_move_constructible_v<variant<int, string>>, "");
|
||||
static_assert(!is_move_constructible_v<variant<AllDeleted, string>>, "");
|
||||
static_assert(!noexcept(variant<int, Empty>(variant<int, Empty>())), "");
|
||||
static_assert(noexcept(variant<int, DefaultNoexcept>(variant<int, DefaultNoexcept>())), "");
|
||||
}
|
||||
|
||||
void arbitrary_ctor()
|
||||
{
|
||||
static_assert(!is_constructible_v<variant<string, string>, const char*>, "");
|
||||
static_assert(is_constructible_v<variant<int, string>, const char*>, "");
|
||||
static_assert(noexcept(variant<int, Empty>(int{})), "");
|
||||
static_assert(noexcept(variant<int, DefaultNoexcept>(int{})), "");
|
||||
static_assert(!noexcept(variant<int, Empty>(Empty{})), "");
|
||||
static_assert(noexcept(variant<int, DefaultNoexcept>(DefaultNoexcept{})), "");
|
||||
}
|
||||
|
||||
void in_place_index_ctor()
|
||||
{
|
||||
variant<string, string> a(in_place<0>, "a");
|
||||
variant<string, string> b(in_place<1>, {'a'});
|
||||
}
|
||||
|
||||
void in_place_type_ctor()
|
||||
{
|
||||
variant<int, string, int> a(in_place<string>, "a");
|
||||
variant<int, string, int> b(in_place<string>, {'a'});
|
||||
static_assert(!is_constructible_v<variant<string, string>, in_place_type_t<string>, const char*>, "");
|
||||
}
|
||||
|
||||
void uses_alloc_ctors()
|
||||
{
|
||||
std::allocator<char> alloc;
|
||||
variant<int> a(allocator_arg, alloc);
|
||||
static_assert(!is_constructible_v<variant<AllDeleted>, allocator_arg_t, std::allocator<char>>, "");
|
||||
{
|
||||
variant<int> b(allocator_arg, alloc, a);
|
||||
static_assert(!is_constructible_v<variant<void>, allocator_arg_t, std::allocator<char>, const variant<void>&>, "");
|
||||
}
|
||||
{
|
||||
variant<int> b(allocator_arg, alloc, std::move(a));
|
||||
static_assert(!is_constructible_v<variant<void>, allocator_arg_t, std::allocator<char>, variant<void>&&>, "");
|
||||
}
|
||||
{
|
||||
variant<string, int> b(allocator_arg, alloc, "a");
|
||||
static_assert(!is_constructible_v<variant<string, string>, allocator_arg_t, std::allocator<char>, const char*>, "");
|
||||
}
|
||||
{
|
||||
variant<string, int> b(allocator_arg, alloc, in_place<0>, "a");
|
||||
variant<string, string> c(allocator_arg, alloc, in_place<1>, "a");
|
||||
}
|
||||
{
|
||||
variant<string, int> b(allocator_arg, alloc, in_place<0>, {'a'});
|
||||
variant<string, string> c(allocator_arg, alloc, in_place<1>, {'a'});
|
||||
}
|
||||
{
|
||||
variant<int, string, int> b(allocator_arg, alloc, in_place<string>, "a");
|
||||
}
|
||||
{
|
||||
variant<int, string, int> b(allocator_arg, alloc, in_place<string>, {'a'});
|
||||
}
|
||||
}
|
||||
|
||||
void dtor()
|
||||
{
|
||||
static_assert(is_destructible_v<variant<int, string>>, "");
|
||||
static_assert(is_destructible_v<variant<AllDeleted, string>>, "");
|
||||
}
|
||||
|
||||
void copy_assign()
|
||||
{
|
||||
static_assert(is_copy_assignable_v<variant<int, string>>, "");
|
||||
static_assert(!is_copy_assignable_v<variant<AllDeleted, string>>, "");
|
||||
{
|
||||
variant<Empty> a;
|
||||
static_assert(!noexcept(a = a), "");
|
||||
}
|
||||
{
|
||||
variant<DefaultNoexcept> a;
|
||||
static_assert(!noexcept(a = a), "");
|
||||
}
|
||||
}
|
||||
|
||||
void move_assign()
|
||||
{
|
||||
static_assert(is_move_assignable_v<variant<int, string>>, "");
|
||||
static_assert(!is_move_assignable_v<variant<AllDeleted, string>>, "");
|
||||
{
|
||||
variant<Empty> a;
|
||||
static_assert(!noexcept(a = std::move(a)), "");
|
||||
}
|
||||
{
|
||||
variant<DefaultNoexcept> a;
|
||||
static_assert(noexcept(a = std::move(a)), "");
|
||||
}
|
||||
}
|
||||
|
||||
void arbitrary_assign()
|
||||
{
|
||||
static_assert(!is_assignable_v<variant<string, string>, const char*>, "");
|
||||
static_assert(is_assignable_v<variant<int, string>, const char*>, "");
|
||||
static_assert(noexcept(variant<int, Empty>() = int{}), "");
|
||||
static_assert(noexcept(variant<int, DefaultNoexcept>() = int{}), "");
|
||||
static_assert(!noexcept(variant<int, Empty>() = Empty{}), "");
|
||||
static_assert(noexcept(variant<int, DefaultNoexcept>() = DefaultNoexcept{}), "");
|
||||
}
|
||||
|
||||
void test_get()
|
||||
{
|
||||
{
|
||||
static_assert(is_same<decltype(get<0>(variant<int, string>())), int&&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(variant<int, string>())), string&&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(variant<int, string&>())), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(variant<int, string&&>())), string&&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(variant<int, const string>())), const string&&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(variant<int, const string&>())), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(variant<int, const string&&>())), const string&&>::value, "");
|
||||
|
||||
static_assert(is_same<decltype(get<int>(variant<int, string>())), int&&>::value, "");
|
||||
static_assert(is_same<decltype(get<string>(variant<int, string>())), string&&>::value, "");
|
||||
static_assert(is_same<decltype(get<string&>(variant<int, string&>())), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<string&&>(variant<int, string&&>())), string&&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string>(variant<int, const string>())), const string&&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string&>(variant<int, const string&>())), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string&&>(variant<int, const string&&>())), const string&&>::value, "");
|
||||
}
|
||||
{
|
||||
variant<int, string> a;
|
||||
variant<int, string&> b;
|
||||
variant<int, string&&> c;
|
||||
variant<int, const string> d;
|
||||
variant<int, const string&> e;
|
||||
variant<int, const string&&> f;
|
||||
|
||||
static_assert(is_same<decltype(get<0>(a)), int&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(a)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(b)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(c)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(e)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(e)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(f)), const string&>::value, "");
|
||||
|
||||
static_assert(is_same<decltype(get<int>(a)), int&>::value, "");
|
||||
static_assert(is_same<decltype(get<string>(a)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<string&>(b)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<string&&>(c)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string>(e)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string&>(e)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string&&>(f)), const string&>::value, "");
|
||||
|
||||
static_assert(is_same<decltype(get_if<0>(&a)), int*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&a)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&b)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&c)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&e)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&e)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&f)), const string*>::value, "");
|
||||
|
||||
static_assert(is_same<decltype(get_if<int>(&a)), int*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<string>(&a)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<string&>(&b)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<string&&>(&c)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<const string>(&e)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<const string&>(&e)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<const string&&>(&f)), const string*>::value, "");
|
||||
}
|
||||
{
|
||||
const variant<int, string> a;
|
||||
const variant<int, string&> b;
|
||||
const variant<int, string&&> c;
|
||||
const variant<int, const string> d;
|
||||
const variant<int, const string&> e;
|
||||
const variant<int, const string&&> f;
|
||||
|
||||
static_assert(is_same<decltype(get<0>(a)), const int&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(a)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(b)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(c)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(d)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(e)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<1>(f)), const string&>::value, "");
|
||||
|
||||
static_assert(is_same<decltype(get<int>(a)), const int&>::value, "");
|
||||
static_assert(is_same<decltype(get<string>(a)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<string&>(b)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<string&&>(c)), string&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string>(d)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string&>(e)), const string&>::value, "");
|
||||
static_assert(is_same<decltype(get<const string&&>(f)), const string&>::value, "");
|
||||
|
||||
static_assert(is_same<decltype(get_if<0>(&a)), const int*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&a)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&b)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&c)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&d)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&e)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<1>(&f)), const string*>::value, "");
|
||||
|
||||
static_assert(is_same<decltype(get_if<int>(&a)), const int*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<string>(&a)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<string&>(&b)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<string&&>(&c)), string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<const string>(&d)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<const string&>(&e)), const string*>::value, "");
|
||||
static_assert(is_same<decltype(get_if<const string&&>(&f)), const string*>::value, "");
|
||||
}
|
||||
}
|
||||
|
||||
void test_relational()
|
||||
{
|
||||
{
|
||||
const variant<int, string> a, b;
|
||||
(void)(a < b);
|
||||
(void)(a > b);
|
||||
(void)(a <= b);
|
||||
(void)(a == b);
|
||||
(void)(a != b);
|
||||
(void)(a >= b);
|
||||
}
|
||||
{
|
||||
const monostate a, b;
|
||||
(void)(a < b);
|
||||
(void)(a > b);
|
||||
(void)(a <= b);
|
||||
(void)(a == b);
|
||||
(void)(a != b);
|
||||
(void)(a >= b);
|
||||
}
|
||||
}
|
||||
|
||||
void test_swap()
|
||||
{
|
||||
variant<int, string> a, b;
|
||||
a.swap(b);
|
||||
swap(a, b);
|
||||
}
|
||||
|
||||
void test_visit()
|
||||
{
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
void operator()(monostate) {}
|
||||
void operator()(const int&) {}
|
||||
};
|
||||
struct CVisitor
|
||||
{
|
||||
void operator()(monostate) const {}
|
||||
void operator()(const int&) const {}
|
||||
};
|
||||
variant<monostate, int&, const int&, int&&, const int&&> a;
|
||||
const variant<monostate, int&, const int&, int&&, const int&&> b;
|
||||
Visitor v;
|
||||
const CVisitor u;
|
||||
static_assert(is_same<void, decltype(visit(Visitor(), a))>::value, "");
|
||||
static_assert(is_same<void, decltype(visit(Visitor(), b))>::value, "");
|
||||
static_assert(is_same<void, decltype(visit(v, a))>::value, "");
|
||||
static_assert(is_same<void, decltype(visit(v, b))>::value, "");
|
||||
static_assert(is_same<void, decltype(visit(u, a))>::value, "");
|
||||
static_assert(is_same<void, decltype(visit(u, b))>::value, "");
|
||||
}
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
bool operator()(int, float) { return false; }
|
||||
bool operator()(int, double) { return false; }
|
||||
bool operator()(char, float) { return false; }
|
||||
bool operator()(char, double) { return false; }
|
||||
};
|
||||
visit(Visitor(), variant<int, char>(), variant<float, double>());
|
||||
}
|
||||
}
|
||||
|
||||
void test_constexpr()
|
||||
{
|
||||
constexpr variant<int> a;
|
||||
static_assert(holds_alternative<int>(a), "");
|
||||
constexpr variant<int, char> b(in_place<0>, int{});
|
||||
static_assert(holds_alternative<int>(b), "");
|
||||
constexpr variant<int, char> c(in_place<int>, int{});
|
||||
static_assert(holds_alternative<int>(c), "");
|
||||
constexpr variant<int, char> d(in_place<1>, char{});
|
||||
static_assert(holds_alternative<char>(d), "");
|
||||
constexpr variant<int, char> e(in_place<char>, char{});
|
||||
static_assert(holds_alternative<char>(e), "");
|
||||
constexpr variant<int, char> f(char{});
|
||||
static_assert(holds_alternative<char>(f), "");
|
||||
|
||||
{
|
||||
struct literal {
|
||||
constexpr literal() = default;
|
||||
};
|
||||
|
||||
struct nonliteral {
|
||||
nonliteral() { }
|
||||
};
|
||||
|
||||
constexpr variant<literal, nonliteral> v{};
|
||||
constexpr variant<literal, nonliteral> v1{in_place<literal>};
|
||||
constexpr variant<literal, nonliteral> v2{in_place<0>};
|
||||
}
|
||||
}
|
||||
|
||||
void test_void()
|
||||
{
|
||||
static_assert(is_same<int&&, decltype(get<int>(variant<int, void>()))>::value, "");
|
||||
static_assert(!is_default_constructible_v<variant<void, int>>, "");
|
||||
static_assert(!is_copy_constructible_v<variant<int, void>>, "");
|
||||
static_assert(!is_move_constructible_v<variant<int, void>>, "");
|
||||
static_assert(!is_copy_assignable_v<variant<int, void>>, "");
|
||||
static_assert(!is_move_assignable_v<variant<int, void>>, "");
|
||||
variant<int, void, string> v;
|
||||
v = 3;
|
||||
v = "asdf";
|
||||
}
|
||||
|
|
@ -0,0 +1,501 @@
|
|||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do run }
|
||||
|
||||
// Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <variant>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct AlwaysThrow
|
||||
{
|
||||
AlwaysThrow() = default;
|
||||
|
||||
AlwaysThrow(const AlwaysThrow&)
|
||||
{ throw nullptr; }
|
||||
|
||||
AlwaysThrow(AlwaysThrow&&)
|
||||
{ throw nullptr; }
|
||||
|
||||
AlwaysThrow& operator=(const AlwaysThrow&)
|
||||
{
|
||||
throw nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AlwaysThrow& operator=(AlwaysThrow&&)
|
||||
{
|
||||
throw nullptr;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
void default_ctor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<monostate, string> v;
|
||||
VERIFY(holds_alternative<monostate>(v));
|
||||
}
|
||||
|
||||
void copy_ctor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<monostate, string> v("a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
variant<monostate, string> u(v);
|
||||
VERIFY(holds_alternative<string>(u));
|
||||
VERIFY(get<string>(u) == "a");
|
||||
}
|
||||
|
||||
void move_ctor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<monostate, string> v("a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
variant<monostate, string> u(std::move(v));
|
||||
VERIFY(holds_alternative<string>(u));
|
||||
VERIFY(get<string>(u) == "a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
}
|
||||
|
||||
void arbitrary_ctor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<int, string> v("a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
VERIFY(get<1>(v) == "a");
|
||||
}
|
||||
|
||||
void copy_assign()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<monostate, string> v("a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
variant<monostate, string> u;
|
||||
u = v;
|
||||
VERIFY(holds_alternative<string>(u));
|
||||
VERIFY(get<string>(u) == "a");
|
||||
}
|
||||
|
||||
void move_assign()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<monostate, string> v("a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
variant<monostate, string> u;
|
||||
u = std::move(v);
|
||||
VERIFY(holds_alternative<string>(u));
|
||||
VERIFY(get<string>(u) == "a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
}
|
||||
|
||||
void arbitrary_assign()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<int, string> v;
|
||||
v = "a";
|
||||
|
||||
VERIFY(holds_alternative<string>(variant<int, string>("a")));
|
||||
VERIFY(get<1>(v) == "a");
|
||||
}
|
||||
|
||||
void dtor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
struct A {
|
||||
A(int& called) : called(called) {}
|
||||
~A() {
|
||||
called++;
|
||||
}
|
||||
int& called;
|
||||
};
|
||||
{
|
||||
int called = 0;
|
||||
{ variant<string, A> a(in_place<1>, called); }
|
||||
VERIFY(called == 1);
|
||||
}
|
||||
{
|
||||
int called = 0;
|
||||
{ variant<string, A> a(in_place<0>); }
|
||||
VERIFY(called == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void in_place_index_ctor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
{
|
||||
variant<int, string> v(in_place<1>, "a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
VERIFY(get<1>(v) == "a");
|
||||
}
|
||||
{
|
||||
variant<int, string> v(in_place<1>, {'a', 'b'});
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
VERIFY(get<1>(v) == "ab");
|
||||
}
|
||||
}
|
||||
|
||||
void in_place_type_ctor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
{
|
||||
variant<int, string> v(in_place<string>, "a");
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
VERIFY(get<1>(v) == "a");
|
||||
}
|
||||
{
|
||||
variant<int, string> v(in_place<string>, {'a', 'b'});
|
||||
VERIFY(holds_alternative<string>(v));
|
||||
VERIFY(get<1>(v) == "ab");
|
||||
}
|
||||
}
|
||||
|
||||
struct UsesAllocatable
|
||||
{
|
||||
template<typename Alloc>
|
||||
UsesAllocatable(std::allocator_arg_t, const Alloc& a)
|
||||
: d(0), a(static_cast<const void*>(&a)) { }
|
||||
|
||||
template<typename Alloc>
|
||||
UsesAllocatable(std::allocator_arg_t, const Alloc& a, const UsesAllocatable&)
|
||||
: d(1), a(static_cast<const void*>(&a)) { }
|
||||
|
||||
template<typename Alloc>
|
||||
UsesAllocatable(std::allocator_arg_t, const Alloc& a, UsesAllocatable&&)
|
||||
: d(2), a(static_cast<const void*>(&a)) { }
|
||||
|
||||
int d;
|
||||
const void* a;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct uses_allocator<UsesAllocatable, std::allocator<char>> : true_type { };
|
||||
}
|
||||
|
||||
void uses_allocator_ctor()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
std::allocator<char> a;
|
||||
variant<UsesAllocatable> v(std::allocator_arg, a);
|
||||
VERIFY(get<0>(v).d == 0);
|
||||
VERIFY(get<0>(v).a == &a);
|
||||
{
|
||||
variant<UsesAllocatable> u(std::allocator_arg, a, v);
|
||||
VERIFY(get<0>(u).d == 1);
|
||||
VERIFY(get<0>(u).a == &a);
|
||||
}
|
||||
{
|
||||
variant<UsesAllocatable> u(std::allocator_arg, a, std::move(v));
|
||||
VERIFY(get<0>(u).d == 2);
|
||||
VERIFY(get<0>(u).a == &a);
|
||||
}
|
||||
}
|
||||
|
||||
void emplace()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<int, string> v;
|
||||
v.emplace<0>(1);
|
||||
VERIFY(get<0>(v) == 1);
|
||||
v.emplace<string>("a");
|
||||
VERIFY(get<string>(v) == "a");
|
||||
v.emplace<1>({'a', 'b'});
|
||||
VERIFY(get<1>(v) == "ab");
|
||||
v.emplace<string>({'a', 'c'});
|
||||
VERIFY(get<string>(v) == "ac");
|
||||
{
|
||||
variant<int, AlwaysThrow> v;
|
||||
AlwaysThrow a;
|
||||
try { v.emplace<1>(a); } catch (nullptr_t) { }
|
||||
VERIFY(v.valueless_by_exception());
|
||||
}
|
||||
{
|
||||
variant<int, AlwaysThrow> v;
|
||||
try { v.emplace<1>(AlwaysThrow{}); } catch (nullptr_t) { }
|
||||
VERIFY(v.valueless_by_exception());
|
||||
}
|
||||
}
|
||||
|
||||
void test_get()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
VERIFY(get<1>(variant<int, string>("a")) == "a");
|
||||
VERIFY(get<string>(variant<int, string>("a")) == "a");
|
||||
{
|
||||
bool caught = false;
|
||||
|
||||
try
|
||||
{
|
||||
get<0>(variant<int, string>("a"));
|
||||
}
|
||||
catch (const bad_variant_access&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
VERIFY(caught);
|
||||
}
|
||||
{
|
||||
bool caught = false;
|
||||
|
||||
try
|
||||
{
|
||||
get<int>(variant<int, string>("a"));
|
||||
}
|
||||
catch (const bad_variant_access&)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
VERIFY(caught);
|
||||
}
|
||||
}
|
||||
|
||||
void test_relational()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
VERIFY((variant<int, string>(2) < variant<int, string>(3)));
|
||||
VERIFY((variant<int, string>(3) == variant<int, string>(3)));
|
||||
VERIFY((variant<int, string>(3) > variant<int, string>(2)));
|
||||
VERIFY((variant<int, string>(3) <= variant<int, string>(3)));
|
||||
VERIFY((variant<int, string>(2) <= variant<int, string>(3)));
|
||||
VERIFY((variant<int, string>(3) >= variant<int, string>(3)));
|
||||
VERIFY((variant<int, string>(3) >= variant<int, string>(2)));
|
||||
VERIFY((variant<int, string>(2) != variant<int, string>(3)));
|
||||
|
||||
VERIFY((variant<int, string>(2) < variant<int, string>("a")));
|
||||
VERIFY((variant<string, int>(2) > variant<string, int>("a")));
|
||||
}
|
||||
|
||||
void test_swap()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
variant<int, string> a("a"), b("b");
|
||||
a.swap(b);
|
||||
VERIFY(get<1>(a) == "b");
|
||||
VERIFY(get<1>(b) == "a");
|
||||
swap(a, b);
|
||||
VERIFY(get<1>(a) == "a");
|
||||
VERIFY(get<1>(b) == "b");
|
||||
}
|
||||
|
||||
void test_visit()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
int operator()(int, float) {
|
||||
return 0;
|
||||
}
|
||||
int operator()(int, double) {
|
||||
return 1;
|
||||
}
|
||||
int operator()(char, float) {
|
||||
return 2;
|
||||
}
|
||||
int operator()(char, double) {
|
||||
return 3;
|
||||
}
|
||||
int operator()(int, float) const {
|
||||
return 5;
|
||||
}
|
||||
int operator()(int, double) const {
|
||||
return 6;
|
||||
}
|
||||
int operator()(char, float) const {
|
||||
return 7;
|
||||
}
|
||||
int operator()(char, double) const {
|
||||
return 8;
|
||||
}
|
||||
} visitor1;
|
||||
VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
|
||||
VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0)) == 1);
|
||||
VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
|
||||
VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
|
||||
|
||||
const auto& visitor2 = visitor1;
|
||||
VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0f)) == 5);
|
||||
VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0)) == 6);
|
||||
VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0f)) == 7);
|
||||
VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0)) == 8);
|
||||
}
|
||||
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
int operator()(int, float) && {
|
||||
return 0;
|
||||
}
|
||||
int operator()(int, double) && {
|
||||
return 1;
|
||||
}
|
||||
int operator()(char, float) && {
|
||||
return 2;
|
||||
}
|
||||
int operator()(char, double) && {
|
||||
return 3;
|
||||
}
|
||||
};
|
||||
VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
|
||||
VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0)) == 1);
|
||||
VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
|
||||
VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
void test_hash()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
unordered_set<variant<int, string>> s;
|
||||
VERIFY(s.emplace(3).second);
|
||||
VERIFY(s.emplace("asdf").second);
|
||||
VERIFY(s.emplace().second);
|
||||
VERIFY(s.size() == 3);
|
||||
VERIFY(!s.emplace(3).second);
|
||||
VERIFY(!s.emplace("asdf").second);
|
||||
VERIFY(!s.emplace().second);
|
||||
VERIFY(s.size() == 3);
|
||||
{
|
||||
struct A
|
||||
{
|
||||
operator int()
|
||||
{
|
||||
throw nullptr;
|
||||
}
|
||||
};
|
||||
variant<int, string> v;
|
||||
try
|
||||
{
|
||||
v.emplace<0>(A{});
|
||||
}
|
||||
catch (nullptr_t)
|
||||
{
|
||||
}
|
||||
VERIFY(v.valueless_by_exception());
|
||||
VERIFY(s.insert(v).second);
|
||||
VERIFY(s.size() == 4);
|
||||
VERIFY(!s.insert(v).second);
|
||||
}
|
||||
}
|
||||
|
||||
void test_valueless_by_exception()
|
||||
{
|
||||
bool test [[gnu::unused]] = true;
|
||||
|
||||
{
|
||||
AlwaysThrow a;
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
variant<int, AlwaysThrow> v(a);
|
||||
}
|
||||
catch (nullptr_t)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
VERIFY(caught);
|
||||
}
|
||||
{
|
||||
AlwaysThrow a;
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
variant<int, AlwaysThrow> v(a);
|
||||
}
|
||||
catch (nullptr_t)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
VERIFY(caught);
|
||||
}
|
||||
{
|
||||
variant<int, AlwaysThrow> v;
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
AlwaysThrow a;
|
||||
v = a;
|
||||
}
|
||||
catch (nullptr_t)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
VERIFY(caught);
|
||||
VERIFY(v.valueless_by_exception());
|
||||
}
|
||||
{
|
||||
variant<int, AlwaysThrow> v;
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
v = AlwaysThrow{};
|
||||
}
|
||||
catch (nullptr_t)
|
||||
{
|
||||
caught = true;
|
||||
}
|
||||
VERIFY(caught);
|
||||
VERIFY(v.valueless_by_exception());
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
default_ctor();
|
||||
copy_ctor();
|
||||
move_ctor();
|
||||
arbitrary_ctor();
|
||||
in_place_index_ctor();
|
||||
in_place_type_ctor();
|
||||
uses_allocator_ctor();
|
||||
copy_assign();
|
||||
move_assign();
|
||||
arbitrary_assign();
|
||||
dtor();
|
||||
emplace();
|
||||
test_get();
|
||||
test_relational();
|
||||
test_swap();
|
||||
test_visit();
|
||||
test_hash();
|
||||
test_valueless_by_exception();
|
||||
}
|
||||
Loading…
Reference in New Issue