[libcxx] Re-implement LWG 2770 again: Fix tuple_size to work with structured bindings
Summary: This patch attempts to re-implement a fix for LWG 2770, but not the actual specified PR. The PR for 2770 specifies tuple_size<T const> as only conditionally providing a `::value` member. However C++17 structured bindings require `tuple_size<T const>` to be complete only if `tuple_size<T>` is also complete. Therefore this patch implements only provides the specialization `tuple_size<T CV>` iff `tuple_size<T>` is a complete type. This fixes http://llvm.org/PR31513. Reviewers: mclow.lists, rsmith, mpark Subscribers: mpark, cfe-commits Differential Revision: https://reviews.llvm.org/D28222 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@291019 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -20,13 +20,6 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
template <class T, class = decltype(std::tuple_size<T>::value)>
|
||||
constexpr bool has_value(int) { return true; }
|
||||
template <class> constexpr bool has_value(long) { return false; }
|
||||
template <class T> constexpr bool has_value() { return has_value<T>(0); }
|
||||
|
||||
struct Dummy {};
|
||||
|
||||
template <class T, std::size_t N>
|
||||
void test()
|
||||
{
|
||||
@@ -40,21 +33,10 @@ void test()
|
||||
std::tuple_size<const volatile T> >::value), "");
|
||||
}
|
||||
|
||||
void test_tuple_size_value_sfinae() {
|
||||
// Test that the ::value member does not exist
|
||||
static_assert(has_value<std::tuple<int> const>(), "");
|
||||
static_assert(has_value<std::pair<int, long> volatile>(), "");
|
||||
static_assert(!has_value<int>(), "");
|
||||
static_assert(!has_value<const int>(), "");
|
||||
static_assert(!has_value<volatile void>(), "");
|
||||
static_assert(!has_value<const volatile std::tuple<int>&>(), "");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test<std::tuple<>, 0>();
|
||||
test<std::tuple<int>, 1>();
|
||||
test<std::tuple<char, int>, 2>();
|
||||
test<std::tuple<char, char*, int>, 3>();
|
||||
test_tuple_size_value_sfinae();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class... Types> class tuple;
|
||||
|
||||
// template <class... Types>
|
||||
// class tuple_size<tuple<Types...>>
|
||||
// : public integral_constant<size_t, sizeof...(Types)> { };
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
struct Dummy1 {};
|
||||
struct Dummy2 {};
|
||||
struct Dummy3 {};
|
||||
|
||||
template <>
|
||||
class std::tuple_size<Dummy1> {
|
||||
public:
|
||||
static size_t value;
|
||||
};
|
||||
|
||||
template <>
|
||||
class std::tuple_size<Dummy2> {
|
||||
public:
|
||||
static void value() {}
|
||||
};
|
||||
|
||||
template <>
|
||||
class std::tuple_size<Dummy3> {};
|
||||
|
||||
int main()
|
||||
{
|
||||
// Test that tuple_size<const T> is not incomplete when tuple_size<T>::value
|
||||
// is well-formed but not a constant expression.
|
||||
{
|
||||
// expected-error@__tuple:* 1 {{is not a constant expression}}
|
||||
(void)std::tuple_size<const Dummy1>::value; // expected-note {{here}}
|
||||
}
|
||||
// Test that tuple_size<const T> is not incomplete when tuple_size<T>::value
|
||||
// is well-formed but not convertible to size_t.
|
||||
{
|
||||
// expected-error@__tuple:* 1 {{value of type 'void ()' is not implicitly convertible to 'unsigned long'}}
|
||||
(void)std::tuple_size<const Dummy2>::value; // expected-note {{here}}
|
||||
}
|
||||
// Test that tuple_size<const T> generates an error when tuple_size<T> is
|
||||
// complete but ::value isn't a constant expression convertible to size_t.
|
||||
{
|
||||
// expected-error@__tuple:* 1 {{no member named 'value'}}
|
||||
(void)std::tuple_size<const Dummy3>::value; // expected-note {{here}}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class... Types> class tuple;
|
||||
|
||||
// template <class... Types>
|
||||
// class tuple_size<tuple<Types...>>
|
||||
// : public integral_constant<size_t, sizeof...(Types)> { };
|
||||
|
||||
// XFAIL: gcc-4.9
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
template <class T, size_t Size = sizeof(std::tuple_size<T>)>
|
||||
constexpr bool is_complete(int) { static_assert(Size > 0, ""); return true; }
|
||||
template <class> constexpr bool is_complete(long) { return false; }
|
||||
template <class T> constexpr bool is_complete() { return is_complete<T>(0); }
|
||||
|
||||
struct Dummy1 {};
|
||||
struct Dummy2 {};
|
||||
|
||||
namespace std {
|
||||
template <> class tuple_size<Dummy1> : public integral_constant<size_t, 0> {};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_complete() {
|
||||
static_assert(is_complete<T>(), "");
|
||||
static_assert(is_complete<const T>(), "");
|
||||
static_assert(is_complete<volatile T>(), "");
|
||||
static_assert(is_complete<const volatile T>(), "");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_incomplete() {
|
||||
static_assert(!is_complete<T>(), "");
|
||||
static_assert(!is_complete<const T>(), "");
|
||||
static_assert(!is_complete<volatile T>(), "");
|
||||
static_assert(!is_complete<const volatile T>(), "");
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
test_complete<std::tuple<> >();
|
||||
test_complete<std::tuple<int&> >();
|
||||
test_complete<std::tuple<int&&, int&, void*>>();
|
||||
test_complete<std::pair<int, long> >();
|
||||
test_complete<std::array<int, 5> >();
|
||||
test_complete<Dummy1>();
|
||||
|
||||
test_incomplete<void>();
|
||||
test_incomplete<int>();
|
||||
test_incomplete<std::tuple<int>&>();
|
||||
test_incomplete<Dummy2>();
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class... Types> class tuple;
|
||||
|
||||
// template <class... Types>
|
||||
// class tuple_size<tuple<Types...>>
|
||||
// : public integral_constant<size_t, sizeof...(Types)> { };
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
// XFAIL: libcpp-no-structured-bindings
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
struct S { int x; };
|
||||
|
||||
void test_decomp_user_type() {
|
||||
{
|
||||
S s{99};
|
||||
auto [m1] = s;
|
||||
auto& [r1] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &s.x);
|
||||
}
|
||||
{
|
||||
S const s{99};
|
||||
auto [m1] = s;
|
||||
auto& [r1] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &s.x);
|
||||
}
|
||||
}
|
||||
|
||||
void test_decomp_tuple() {
|
||||
typedef std::tuple<int> T;
|
||||
{
|
||||
T s{99};
|
||||
auto [m1] = s;
|
||||
auto& [r1] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &std::get<0>(s));
|
||||
}
|
||||
{
|
||||
T const s{99};
|
||||
auto [m1] = s;
|
||||
auto& [r1] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &std::get<0>(s));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_decomp_pair() {
|
||||
typedef std::pair<int, double> T;
|
||||
{
|
||||
T s{99, 42.1};
|
||||
auto [m1, m2] = s;
|
||||
auto& [r1, r2] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &std::get<0>(s));
|
||||
}
|
||||
{
|
||||
T const s{99, 42.1};
|
||||
auto [m1, m2] = s;
|
||||
auto& [r1, r2] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &std::get<0>(s));
|
||||
}
|
||||
}
|
||||
|
||||
void test_decomp_array() {
|
||||
typedef std::array<int, 3> T;
|
||||
{
|
||||
T s{{99, 42, -1}};
|
||||
auto [m1, m2, m3] = s;
|
||||
auto& [r1, r2, r3] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &std::get<0>(s));
|
||||
}
|
||||
{
|
||||
T const s{{99, 42, -1}};
|
||||
auto [m1, m2, m3] = s;
|
||||
auto& [r1, r2, r3] = s;
|
||||
assert(m1 == 99);
|
||||
assert(&r1 == &std::get<0>(s));
|
||||
}
|
||||
}
|
||||
|
||||
struct Test {
|
||||
int x;
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
int get(Test const&) { static_assert(N == 0, ""); return -1; }
|
||||
|
||||
template <>
|
||||
class std::tuple_element<0, Test> {
|
||||
public:
|
||||
typedef int type;
|
||||
};
|
||||
|
||||
void test_before_tuple_size_specialization() {
|
||||
Test const t{99};
|
||||
auto& [p] = t;
|
||||
assert(p == 99);
|
||||
}
|
||||
|
||||
template <>
|
||||
class std::tuple_size<Test> {
|
||||
public:
|
||||
static const size_t value = 1;
|
||||
};
|
||||
|
||||
void test_after_tuple_size_specialization() {
|
||||
Test const t{99};
|
||||
auto& [p] = t;
|
||||
assert(p == -1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_decomp_user_type();
|
||||
test_decomp_tuple();
|
||||
test_decomp_pair();
|
||||
test_decomp_array();
|
||||
test_before_tuple_size_specialization();
|
||||
test_after_tuple_size_specialization();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class... Types> class tuple;
|
||||
|
||||
// template <class... Types>
|
||||
// class tuple_size<tuple<Types...>>
|
||||
// : public integral_constant<size_t, sizeof...(Types)> { };
|
||||
|
||||
// XFAIL: gcc-4.9
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
template <class T, class = decltype(std::tuple_size<T>::value)>
|
||||
constexpr bool has_value(int) { return true; }
|
||||
template <class> constexpr bool has_value(long) { return false; }
|
||||
template <class T> constexpr bool has_value() { return has_value<T>(0); }
|
||||
|
||||
struct Dummy {};
|
||||
|
||||
int main() {
|
||||
// Test that the ::value member does not exist
|
||||
static_assert(has_value<std::tuple<int> const>(), "");
|
||||
static_assert(has_value<std::pair<int, long> volatile>(), "");
|
||||
static_assert(!has_value<int>(), "");
|
||||
static_assert(!has_value<const int>(), "");
|
||||
static_assert(!has_value<volatile void>(), "");
|
||||
static_assert(!has_value<const volatile std::tuple<int>&>(), "");
|
||||
}
|
||||
Reference in New Issue
Block a user