Created
July 10, 2015 23:14
-
-
Save EricWF/dc34df961cd51cce5a30 to your computer and use it in GitHub Desktop.
Tuple Bug
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <type_traits> | |
| #include <tuple> | |
| #include <cassert> | |
| template <bool Pred, class Then = bool> | |
| using EnableIf = typename std::enable_if<Pred, Then>::type; | |
| template <bool Pred> | |
| using BoolT = std::integral_constant<bool, Pred>; | |
| template <class ...Args> | |
| using LazyAnd = | |
| #ifdef _LIBCPP_VERSION | |
| std::__lazy_and<Args...>; | |
| #else | |
| std::__and_<Args...>; | |
| #endif | |
| /** | |
| * MyTupleImp - A class that provides some of the std::tuple constructors. | |
| * If UseExplicit is true then the Tuple(Uargs&&...) is explicit otherwise | |
| * it is implicit. | |
| */ | |
| template <bool UseExplicit, class ...Args> | |
| struct MyTupleImp { | |
| /////////////////////////////////////////////////////////////////////////// | |
| // Explicit C++11 Args Converting Constructor | |
| template <class ...UArgs, | |
| EnableIf<LazyAnd< | |
| BoolT<UseExplicit>, | |
| std::is_convertible<UArgs, Args>... | |
| >::value> = false> | |
| explicit | |
| MyTupleImp(UArgs&&...) : LastCalled(ConvertArgs) {} | |
| /////////////////////////////////////////////////////////////////////////// | |
| // Implicit C++17 Args Converting Constructor | |
| template <class ...UArgs, | |
| EnableIf<LazyAnd< | |
| BoolT<!UseExplicit>, | |
| std::is_convertible<UArgs, Args>... | |
| >::value> = false> | |
| MyTupleImp(UArgs&&...) : LastCalled(ConvertArgs) {} | |
| /////////////////////////////////////////////////////////////////////////// | |
| // C++11 and C++17 Tuple Converting Constructor | |
| template <class ...UArgs, | |
| class = EnableIf<LazyAnd< | |
| std::is_convertible<UArgs, Args>... | |
| >::value>> | |
| MyTupleImp(MyTupleImp<UseExplicit, UArgs...>&&) : LastCalled(ConvertTuple) {} | |
| enum CtorCalled { | |
| ConvertArgs, | |
| ConvertTuple | |
| }; | |
| int LastCalled; | |
| }; | |
| // Provides the C++11 explicit Tuple(UArgs&&...) constructor. | |
| template <class ...Args> | |
| using Tuple11 = MyTupleImp<true, Args...>; | |
| // Provides the C++17 implicit Tuple(UArgs&&...) constructor. | |
| template <class ...Args> | |
| using Tuple17 = MyTupleImp<false, Args...>; | |
| int main() { | |
| { // C++11 Tuple Passes. | |
| using Tuple = Tuple11<int>; | |
| using NestedTuple = Tuple11< Tuple11<int>&& >; | |
| Tuple t(42); | |
| NestedTuple t2(std::move(t)); | |
| assert(t2.LastCalled == NestedTuple::ConvertArgs); | |
| } | |
| { // C++17 Tuple FAILS! | |
| using Tuple = Tuple17<int>; | |
| using NestedTuple = Tuple17< Tuple17<int>&& >; | |
| Tuple t(42); | |
| NestedTuple t2(std::move(t)); | |
| assert(t2.LastCalled == NestedTuple::ConvertArgs); | |
| // Tuple(TupleLike&&) is called with | |
| // with Tuple = Tuple17< Tuple17<int>&& > | |
| // TupleLike = Tuple17<int>&& | |
| // -- Which calls -- | |
| // TupleLeaf< Tuple17<int>&& >( int && ) | |
| // -- Which constructs -- | |
| // Tuple17<int>&& Leaf from int && | |
| // Leaf is constructed from a temporary Tuple<int>. | |
| // The temporary goes out of scope immediately. | |
| // -------------------- | |
| // NestedTuple now contains a dangling reference. | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment