Defining this macro and then building libc++ with hidden visibility gives a
build of libc++ which does not export any symbols, which can be useful when
building statically for inclusion into another library.
+
+**_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION**:
+ This macro is used to re-enable an extension in `std::tuple` which allowed
+ it to be implicitly constructed from fewer initializers than contained
+ elements. Elements without an initializer are default constructed. For example:
+
+ .. code-block:: cpp
+
+ std::tuple<std::string, int, std::error_code> foo() {
+ return {"hello world", 42}; // default constructs error_code
+ }
+
+
+ Since libc++ 4.0 this extension has been disabled by default. This macro
+ may be defined to re-enable it in order to support existing code that depends
+ on the extension. New use of this extension should be discouraged.
+ See `PR 27374 <http://llvm.org/PR27374>`_ for more information.
+
+ Note: The "reduced-arity-initialization" extension is still offered but only
+ for explicit conversions. Example:
+
+ .. code-block:: cpp
+
+ auto foo() {
+ using Tup = std::tuple<std::string, int, std::error_code>;
+ return Tup{"hello world", 42}; // explicit constructor called. OK.
+ }
base base_;
+#if defined(_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION)
+ static constexpr bool _EnableImplicitReducedArityExtension = true;
+#else
+ static constexpr bool _EnableImplicitReducedArityExtension = false;
+#endif
+
template <class ..._Args>
struct _PackExpandsToThisTuple : false_type {};
) {}
template <class ..._Up,
+ bool _PackIsTuple = _PackExpandsToThisTuple<_Up...>::value,
typename enable_if
<
_CheckArgsConstructor<
- sizeof...(_Up) <= sizeof...(_Tp)
- && !_PackExpandsToThisTuple<_Up...>::value
+ sizeof...(_Up) == sizeof...(_Tp)
+ && !_PackIsTuple
+ >::template __enable_implicit<_Up...>() ||
+ _CheckArgsConstructor<
+ _EnableImplicitReducedArityExtension
+ && sizeof...(_Up) < sizeof...(_Tp)
+ && !_PackIsTuple
>::template __enable_implicit<_Up...>(),
bool
>::type = false
_CheckArgsConstructor<
sizeof...(_Up) <= sizeof...(_Tp)
&& !_PackExpandsToThisTuple<_Up...>::value
- >::template __enable_explicit<_Up...>(),
+ >::template __enable_explicit<_Up...>() ||
+ _CheckArgsConstructor<
+ !_EnableImplicitReducedArityExtension
+ && sizeof...(_Up) < sizeof...(_Tp)
+ && !_PackExpandsToThisTuple<_Up...>()
+ >::template __enable_implicit<_Up...>(),
bool
>::type = false
>
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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... UTypes>
+// explicit tuple(UTypes&&... u);
+
+// UNSUPPORTED: c++98, c++03
+
+#include <tuple>
+#include <cassert>
+#include <type_traits>
+#include <string>
+#include <system_error>
+
+#include "test_macros.h"
+#include "test_convertible.hpp"
+#include "MoveOnly.h"
+
+#if defined(_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION)
+#error This macro should not be defined by default
+#endif
+
+struct NoDefault { NoDefault() = delete; };
+
+
+// Make sure the _Up... constructor SFINAEs out when the types that
+// are not explicitly initialized are not all default constructible.
+// Otherwise, std::is_constructible would return true but instantiating
+// the constructor would fail.
+void test_default_constructible_extension_sfinae()
+{
+ typedef MoveOnly MO;
+ typedef NoDefault ND;
+ {
+ typedef std::tuple<MO, ND> Tuple;
+ static_assert(!std::is_constructible<Tuple, MO>::value, "");
+ static_assert(std::is_constructible<Tuple, MO, ND>::value, "");
+ static_assert(test_convertible<Tuple, MO, ND>(), "");
+ }
+ {
+ typedef std::tuple<MO, MO, ND> Tuple;
+ static_assert(!std::is_constructible<Tuple, MO, MO>::value, "");
+ static_assert(std::is_constructible<Tuple, MO, MO, ND>::value, "");
+ static_assert(test_convertible<Tuple, MO, MO, ND>(), "");
+ }
+ {
+ // Same idea as above but with a nested tuple type.
+ typedef std::tuple<MO, ND> Tuple;
+ typedef std::tuple<MO, Tuple, MO, MO> NestedTuple;
+
+ static_assert(!std::is_constructible<
+ NestedTuple, MO, MO, MO, MO>::value, "");
+ static_assert(std::is_constructible<
+ NestedTuple, MO, Tuple, MO, MO>::value, "");
+ }
+}
+
+using ExplicitTup = std::tuple<std::string, int, std::error_code>;
+ExplicitTup doc_example() {
+ return ExplicitTup{"hello world", 42}; // explicit constructor called. OK.
+}
+
+// Test that the example given in UsingLibcxx.rst actually works.
+void test_example_from_docs() {
+ auto tup = doc_example();
+ assert(std::get<0>(tup) == "hello world");
+ assert(std::get<1>(tup) == 42);
+ assert(std::get<2>(tup) == std::error_code{});
+}
+
+int main()
+{
+ {
+ using E = MoveOnly;
+ using Tup = std::tuple<E, E, E>;
+ // Test that the reduced arity initialization extension is only
+ // allowed on the explicit constructor.
+ static_assert(test_convertible<Tup, E, E, E>(), "");
+
+ Tup t(E(0), E(1));
+ static_assert(std::is_constructible<Tup, E, E>::value, "");
+ static_assert(!test_convertible<Tup, E, E>(), "");
+ assert(std::get<0>(t) == 0);
+ assert(std::get<1>(t) == 1);
+ assert(std::get<2>(t) == MoveOnly());
+
+ Tup t2(E(0));
+ static_assert(std::is_constructible<Tup, E>::value, "");
+ static_assert(!test_convertible<Tup, E>(), "");
+ assert(std::get<0>(t) == 0);
+ assert(std::get<1>(t) == E());
+ assert(std::get<2>(t) == E());
+ }
+ // Check that SFINAE is properly applied with the default reduced arity
+ // constructor extensions.
+ test_default_constructible_extension_sfinae();
+ test_example_from_docs();
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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... UTypes>
+// explicit tuple(UTypes&&... u);
+
+// UNSUPPORTED: c++98, c++03
+
+// MODULES_DEFINES: _LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION
+#define _LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION
+#include <tuple>
+#include <cassert>
+#include <type_traits>
+#include <string>
+#include <system_error>
+
+#include "test_macros.h"
+#include "test_convertible.hpp"
+#include "MoveOnly.h"
+
+
+struct NoDefault { NoDefault() = delete; };
+
+
+// Make sure the _Up... constructor SFINAEs out when the types that
+// are not explicitly initialized are not all default constructible.
+// Otherwise, std::is_constructible would return true but instantiating
+// the constructor would fail.
+void test_default_constructible_extension_sfinae()
+{
+ typedef MoveOnly MO;
+ typedef NoDefault ND;
+ {
+ typedef std::tuple<MO, ND> Tuple;
+ static_assert(!std::is_constructible<Tuple, MO>::value, "");
+ static_assert(std::is_constructible<Tuple, MO, ND>::value, "");
+ static_assert(test_convertible<Tuple, MO, ND>(), "");
+ }
+ {
+ typedef std::tuple<MO, MO, ND> Tuple;
+ static_assert(!std::is_constructible<Tuple, MO, MO>::value, "");
+ static_assert(std::is_constructible<Tuple, MO, MO, ND>::value, "");
+ static_assert(test_convertible<Tuple, MO, MO, ND>(), "");
+ }
+ {
+ // Same idea as above but with a nested tuple type.
+ typedef std::tuple<MO, ND> Tuple;
+ typedef std::tuple<MO, Tuple, MO, MO> NestedTuple;
+
+ static_assert(!std::is_constructible<
+ NestedTuple, MO, MO, MO, MO>::value, "");
+ static_assert(std::is_constructible<
+ NestedTuple, MO, Tuple, MO, MO>::value, "");
+ }
+ {
+ typedef std::tuple<MO, int> Tuple;
+ typedef std::tuple<MO, Tuple, MO, MO> NestedTuple;
+
+ static_assert(std::is_constructible<
+ NestedTuple, MO, MO, MO, MO>::value, "");
+ static_assert(test_convertible<
+ NestedTuple, MO, MO, MO, MO>(), "");
+
+ static_assert(std::is_constructible<
+ NestedTuple, MO, Tuple, MO, MO>::value, "");
+ static_assert(test_convertible<
+ NestedTuple, MO, Tuple, MO, MO>(), "");
+ }
+}
+
+std::tuple<std::string, int, std::error_code> doc_example() {
+ return {"hello world", 42};
+}
+
+// Test that the example given in UsingLibcxx.rst actually works.
+void test_example_from_docs() {
+ auto tup = doc_example();
+ assert(std::get<0>(tup) == "hello world");
+ assert(std::get<1>(tup) == 42);
+ assert(std::get<2>(tup) == std::error_code{});
+}
+
+int main()
+{
+
+ {
+ using E = MoveOnly;
+ using Tup = std::tuple<E, E, E>;
+ static_assert(test_convertible<Tup, E, E, E>(), "");
+
+ Tup t = {E(0), E(1)};
+ static_assert(test_convertible<Tup, E, E>(), "");
+ assert(std::get<0>(t) == 0);
+ assert(std::get<1>(t) == 1);
+ assert(std::get<2>(t) == MoveOnly());
+
+ Tup t2 = {E(0)};
+ static_assert(test_convertible<Tup, E>(), "");
+ assert(std::get<0>(t) == 0);
+ assert(std::get<1>(t) == E());
+ assert(std::get<2>(t) == E());
+ }
+ // Check that SFINAE is properly applied with the default reduced arity
+ // constructor extensions.
+ test_default_constructible_extension_sfinae();
+ test_example_from_docs();
+}
#include <type_traits>
#include "test_macros.h"
+#include "test_convertible.hpp"
#include "MoveOnly.h"
#if TEST_STD_VER > 11
// extensions
#ifdef _LIBCPP_VERSION
{
- std::tuple<MoveOnly, MoveOnly, MoveOnly> t(MoveOnly(0),
- MoveOnly(1));
+ using E = MoveOnly;
+ using Tup = std::tuple<E, E, E>;
+ // Test that the reduced arity initialization extension is only
+ // allowed on the explicit constructor.
+ static_assert(test_convertible<Tup, E, E, E>(), "");
+
+ Tup t(E(0), E(1));
+ static_assert(!test_convertible<Tup, E, E>(), "");
assert(std::get<0>(t) == 0);
assert(std::get<1>(t) == 1);
assert(std::get<2>(t) == MoveOnly());
- }
- {
- std::tuple<MoveOnly, MoveOnly, MoveOnly> t(MoveOnly(0));
+
+ Tup t2(E(0));
+ static_assert(!test_convertible<Tup, E>(), "");
assert(std::get<0>(t) == 0);
- assert(std::get<1>(t) == MoveOnly());
- assert(std::get<2>(t) == MoveOnly());
+ assert(std::get<1>(t) == E());
+ assert(std::get<2>(t) == E());
}
#endif
#if TEST_STD_VER > 11