Hi mclow.lists, ldionne, K-ballo,
There are two conflicting constructors in tuple:
```
template <class ..._Up>
tuple(_Up&&...) // Construct from elements.
template <class _Tuple>
tuple(_Tuple&&) // copy/move constructor.
```
When the length of the tuple is 1 and the first element is a tuple then we can
incorrectly select the copy/move constructor. This patch adds more SFINAE to
try and prevent this.
This patch likely needs more work.
http://reviews.llvm.org/D8178
Files:
include/tuple
test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
Index: include/tuple
===================================================================
--- include/tuple
+++ include/tuple
@@ -500,6 +500,7 @@
class _LIBCPP_TYPE_VIS_ONLY tuple
{
typedef __tuple_impl<typename __make_tuple_indices<sizeof...(_Tp)>::type,
_Tp...> base;
+ typedef typename tuple_element<0, __tuple_types<_Tp...>>::type _First;
base base_;
@@ -655,6 +656,8 @@
template <class _Tuple,
typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ __tuple_convertible<tuple<_Tuple>,
__tuple_types<_First>>::value) &&
__tuple_convertible<_Tuple, tuple>::value,
bool
>::type = false
@@ -666,6 +669,9 @@
template <class _Tuple,
typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ (__tuple_convertible<tuple<_Tuple>,
__tuple_types<_First>>::value ||
+ __tuple_constructible<tuple<_Tuple>,
__tuple_types<_First>>::value)) &&
__tuple_constructible<_Tuple, tuple>::value &&
!__tuple_convertible<_Tuple, tuple>::value,
bool
@@ -679,6 +685,8 @@
template <class _Alloc, class _Tuple,
class = typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ __tuple_convertible<tuple<_Tuple>,
__tuple_types<_First>>::value) &&
__tuple_convertible<_Tuple, tuple>::value
>::type
>
Index:
test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
@@ -0,0 +1,44 @@
+#include <cassert>
+#include <tuple>
+#include <memory>
+
+#include "tracked_value.h"
+
+int main()
+{
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ // This selects the wrong constructor and constructs std::tuple<Tracked>&&
+ // from a temporary.
+ std::tuple<std::tuple<TrackedValue>&&> t2(std::move(t1));
+ // This moves from the reference constructed from the temporary.
+ std::tuple<std::tuple<TrackedValue>> t3(std::move(t2));
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> const &> t2(t1);
+ std::tuple<std::tuple<TrackedValue>> t3(t2);
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> &> t2(t1);
+ std::tuple<std::tuple<TrackedValue>> t3(t2);
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue>&&> t2(std::move(t1));
+ std::allocator<void> a;
+ std::tuple<std::tuple<TrackedValue>> t3(std::allocator_arg, a,
std::move(t2));
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> const &> t2(t1);
+ std::allocator<void> a;
+ std::tuple<std::tuple<TrackedValue>> t3(std::allocator_arg, a, t2);
+ }
+}
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/tuple
===================================================================
--- include/tuple
+++ include/tuple
@@ -500,6 +500,7 @@
class _LIBCPP_TYPE_VIS_ONLY tuple
{
typedef __tuple_impl<typename __make_tuple_indices<sizeof...(_Tp)>::type, _Tp...> base;
+ typedef typename tuple_element<0, __tuple_types<_Tp...>>::type _First;
base base_;
@@ -655,6 +656,8 @@
template <class _Tuple,
typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ __tuple_convertible<tuple<_Tuple>, __tuple_types<_First>>::value) &&
__tuple_convertible<_Tuple, tuple>::value,
bool
>::type = false
@@ -666,6 +669,9 @@
template <class _Tuple,
typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ (__tuple_convertible<tuple<_Tuple>, __tuple_types<_First>>::value ||
+ __tuple_constructible<tuple<_Tuple>, __tuple_types<_First>>::value)) &&
__tuple_constructible<_Tuple, tuple>::value &&
!__tuple_convertible<_Tuple, tuple>::value,
bool
@@ -679,6 +685,8 @@
template <class _Alloc, class _Tuple,
class = typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ __tuple_convertible<tuple<_Tuple>, __tuple_types<_First>>::value) &&
__tuple_convertible<_Tuple, tuple>::value
>::type
>
Index: test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
@@ -0,0 +1,44 @@
+#include <cassert>
+#include <tuple>
+#include <memory>
+
+#include "tracked_value.h"
+
+int main()
+{
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ // This selects the wrong constructor and constructs std::tuple<Tracked>&&
+ // from a temporary.
+ std::tuple<std::tuple<TrackedValue>&&> t2(std::move(t1));
+ // This moves from the reference constructed from the temporary.
+ std::tuple<std::tuple<TrackedValue>> t3(std::move(t2));
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> const &> t2(t1);
+ std::tuple<std::tuple<TrackedValue>> t3(t2);
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> &> t2(t1);
+ std::tuple<std::tuple<TrackedValue>> t3(t2);
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue>&&> t2(std::move(t1));
+ std::allocator<void> a;
+ std::tuple<std::tuple<TrackedValue>> t3(std::allocator_arg, a, std::move(t2));
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> const &> t2(t1);
+ std::allocator<void> a;
+ std::tuple<std::tuple<TrackedValue>> t3(std::allocator_arg, a, t2);
+ }
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits