From 13c90a57165be999c505cfcfaf38755ed518b103 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 6 Nov 2019 12:02:41 +0000 Subject: [PATCH] [libc++][P0202] Marked algorithms copy/copy_n/copy_if/copy_backward constexpr Thanks to Michael Park for the patch. Differential Revision: https://reviews.llvm.org/D68837 --- libcxx/include/algorithm | 66 +++++++++---- libcxx/include/iterator | 8 +- .../alg.copy/copy.pass.cpp | 92 +++++++++---------- .../alg.copy/copy_backward.pass.cpp | 51 +++++------ .../alg.copy/copy_if.pass.cpp | 102 ++++++++++----------- .../alg.copy/copy_n.pass.cpp | 100 ++++++++++---------- libcxx/test/support/test_iterators.h | 14 +-- libcxx/test/support/test_macros.h | 6 ++ libcxx/test/support/user_defined_integral.h | 8 +- 9 files changed, 233 insertions(+), 214 deletions(-) diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 55ea5eb..419ec2c 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -167,20 +167,20 @@ template Size count, const T& value, BinaryPredicate pred); template - OutputIterator + constexpr OutputIterator // constexpr in C++20 copy(InputIterator first, InputIterator last, OutputIterator result); template - OutputIterator + constexpr OutputIterator // constexpr in C++20 copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate pred); template - OutputIterator + constexpr OutputIterator // constexpr in C++20 copy_n(InputIterator first, Size n, OutputIterator result); template - BidirectionalIterator2 + constexpr BidirectionalIterator2 // constexpr in C++20 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result); @@ -1631,7 +1631,7 @@ search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const // copy template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter __unwrap_iter(_Iter __i) { @@ -1639,7 +1639,7 @@ __unwrap_iter(_Iter __i) } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1693,15 +1693,23 @@ __unwrap_iter(__wrap_iter<_Tp*> __i) #endif // _LIBCPP_DEBUG_LEVEL < 2 template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator -__copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +__copy_constexpr(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { for (; __first != __last; ++__first, (void) ++__result) *__result = *__first; return __result; } +template +inline _LIBCPP_INLINE_VISIBILITY +_OutputIterator +__copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ + return __copy_constexpr(__first, __last, __result); +} + template inline _LIBCPP_INLINE_VISIBILITY typename enable_if @@ -1719,25 +1727,39 @@ __copy(_Tp* __first, _Tp* __last, _Up* __result) } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { - return _VSTD::__copy(__unwrap_iter(__first), __unwrap_iter(__last), __unwrap_iter(__result)); + if (__libcpp_is_constant_evaluated()) { + return _VSTD::__copy_constexpr( + __unwrap_iter(__first), __unwrap_iter(__last), __unwrap_iter(__result)); + } else { + return _VSTD::__copy( + __unwrap_iter(__first), __unwrap_iter(__last), __unwrap_iter(__result)); + } } // copy_backward template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator -__copy_backward(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __result) +__copy_backward_constexpr(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __result) { while (__first != __last) *--__result = *--__last; return __result; } +template +inline _LIBCPP_INLINE_VISIBILITY +_OutputIterator +__copy_backward(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __result) +{ + return __copy_backward_constexpr(__first, __last, __result); +} + template inline _LIBCPP_INLINE_VISIBILITY typename enable_if @@ -1758,20 +1780,26 @@ __copy_backward(_Tp* __first, _Tp* __last, _Up* __result) } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _BidirectionalIterator2 copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) { - return _VSTD::__copy_backward(__unwrap_iter(__first), - __unwrap_iter(__last), - __unwrap_iter(__result)); + if (__libcpp_is_constant_evaluated()) { + return _VSTD::__copy_backward_constexpr(__unwrap_iter(__first), + __unwrap_iter(__last), + __unwrap_iter(__result)); + } else { + return _VSTD::__copy_backward(__unwrap_iter(__first), + __unwrap_iter(__last), + __unwrap_iter(__result)); + } } // copy_if template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred) @@ -1790,7 +1818,7 @@ copy_if(_InputIterator __first, _InputIterator __last, // copy_n template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if < __is_input_iterator<_InputIterator>::value && @@ -1816,7 +1844,7 @@ copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if < __is_random_access_iterator<_InputIterator>::value, diff --git a/libcxx/include/iterator b/libcxx/include/iterator index 30801ea..c5c0f66 100644 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -1304,8 +1304,8 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter<_Iter> operator+(typename __wrap_iter<_Iter>::difference_type, __wrap_iter<_Iter>) _NOEXCEPT; -template _Op _LIBCPP_INLINE_VISIBILITY copy(_Ip, _Ip, _Op); -template _B2 _LIBCPP_INLINE_VISIBILITY copy_backward(_B1, _B1, _B2); +template _Op _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 copy(_Ip, _Ip, _Op); +template _B2 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 copy_backward(_B1, _B1, _B2); template _Op _LIBCPP_INLINE_VISIBILITY move(_Ip, _Ip, _Op); template _B2 _LIBCPP_INLINE_VISIBILITY move_backward(_B1, _B1, _B2); @@ -1515,8 +1515,8 @@ private: __wrap_iter<_Iter1> operator+(typename __wrap_iter<_Iter1>::difference_type, __wrap_iter<_Iter1>) _NOEXCEPT; - template friend _Op copy(_Ip, _Ip, _Op); - template friend _B2 copy_backward(_B1, _B1, _B2); + template friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _Op copy(_Ip, _Ip, _Op); + template friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _B2 copy_backward(_B1, _B1, _B2); template friend _Op move(_Ip, _Ip, _Op); template friend _B2 move_backward(_B1, _B1, _B2); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp index 9dcace7..cc99859 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp @@ -18,21 +18,9 @@ #include "test_macros.h" #include "test_iterators.h" -// #if TEST_STD_VER > 17 -// TEST_CONSTEXPR bool test_constexpr() { -// int ia[] = {1, 2, 3, 4, 5}; -// int ic[] = {6, 6, 6, 6, 6, 6, 6}; -// -// auto p = std::copy(std::begin(ia), std::end(ia), std::begin(ic)); -// return std::equal(std::begin(ia), std::end(ia), std::begin(ic), p) -// && std::all_of(p, std::end(ic), [](int a){return a == 6;}) -// ; -// } -// #endif - template -void -test() +TEST_CONSTEXPR_CXX20 void +test_copy() { const unsigned N = 1000; int ia[N]; @@ -46,46 +34,54 @@ test() assert(ia[i] == ib[i]); } -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool +test() { - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test_copy, output_iterator >(); + test_copy, input_iterator >(); + test_copy, forward_iterator >(); + test_copy, bidirectional_iterator >(); + test_copy, random_access_iterator >(); + test_copy, int*>(); - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test_copy, output_iterator >(); + test_copy, input_iterator >(); + test_copy, forward_iterator >(); + test_copy, bidirectional_iterator >(); + test_copy, random_access_iterator >(); + test_copy, int*>(); - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test_copy, output_iterator >(); + test_copy, input_iterator >(); + test_copy, forward_iterator >(); + test_copy, bidirectional_iterator >(); + test_copy, random_access_iterator >(); + test_copy, int*>(); - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test_copy, output_iterator >(); + test_copy, input_iterator >(); + test_copy, forward_iterator >(); + test_copy, bidirectional_iterator >(); + test_copy, random_access_iterator >(); + test_copy, int*>(); - test >(); - test >(); - test >(); - test >(); - test >(); - test(); + test_copy >(); + test_copy >(); + test_copy >(); + test_copy >(); + test_copy >(); + test_copy(); + + return true; +} + +int main(int, char**) +{ + test(); -// #if TEST_STD_VER > 17 -// static_assert(test_constexpr()); -// #endif +#if TEST_STD_VER > 17 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp index 2f012d5..0678257 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp @@ -20,22 +20,9 @@ #include "test_iterators.h" #include "user_defined_integral.h" -// #if TEST_STD_VER > 17 -// TEST_CONSTEXPR bool test_constexpr() { -// int ia[] = {1, 2, 3, 4, 5}; -// int ic[] = {6, 6, 6, 6, 6, 6, 6}; -// -// size_t N = std::size(ia); -// auto p = std::copy_backward(std::begin(ia), std::end(ia), std::begin(ic) + N); -// return std::equal(std::begin(ic), p, std::begin(ia)) -// && std::all_of(p, std::end(ic), [](int a){return a == 6;}) -// ; -// } -// #endif - template -void -test() +TEST_CONSTEXPR_CXX20 void +test_copy_backward() { const unsigned N = 1000; int ia[N]; @@ -49,23 +36,31 @@ test() assert(ia[i] == ib[i]); } -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool +test() { - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test_copy_backward, bidirectional_iterator >(); + test_copy_backward, random_access_iterator >(); + test_copy_backward, int*>(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); + test_copy_backward, bidirectional_iterator >(); + test_copy_backward, random_access_iterator >(); + test_copy_backward, int*>(); - test >(); - test >(); - test(); + test_copy_backward >(); + test_copy_backward >(); + test_copy_backward(); + + return true; +} + +int main(int, char**) +{ + test(); -// #if TEST_STD_VER > 17 -// static_assert(test_constexpr()); -// #endif +#if TEST_STD_VER > 17 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_if.pass.cpp index 903bcbe..407e18f 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_if.pass.cpp @@ -20,26 +20,14 @@ #include "test_macros.h" #include "test_iterators.h" -// #if TEST_STD_VER > 17 -// TEST_CONSTEXPR bool test_constexpr() { -// int ia[] = {2, 4, 6, 8, 6}; -// int ic[] = {0, 0, 0, 0, 0, 0}; -// -// auto p = std::copy_if(std::begin(ia), std::end(ia), std::begin(ic), is6); -// return std::all_of(std::begin(ic), p, [](int a){return a == 6;}) -// && std::all_of(p, std::end(ic), [](int a){return a == 0;}) -// ; -// } -// #endif - struct Pred { - bool operator()(int i) {return i % 3 == 0;} + TEST_CONSTEXPR_CXX14 bool operator()(int i) {return i % 3 == 0;} }; template -void -test() +TEST_CONSTEXPR_CXX20 void +test_copy_if() { const unsigned N = 1000; int ia[N]; @@ -53,46 +41,54 @@ test() assert(ib[i] % 3 == 0); } +TEST_CONSTEXPR_CXX20 bool +test() +{ + test_copy_if, output_iterator >(); + test_copy_if, input_iterator >(); + test_copy_if, forward_iterator >(); + test_copy_if, bidirectional_iterator >(); + test_copy_if, random_access_iterator >(); + test_copy_if, int*>(); + + test_copy_if, output_iterator >(); + test_copy_if, input_iterator >(); + test_copy_if, forward_iterator >(); + test_copy_if, bidirectional_iterator >(); + test_copy_if, random_access_iterator >(); + test_copy_if, int*>(); + + test_copy_if, output_iterator >(); + test_copy_if, input_iterator >(); + test_copy_if, forward_iterator >(); + test_copy_if, bidirectional_iterator >(); + test_copy_if, random_access_iterator >(); + test_copy_if, int*>(); + + test_copy_if, output_iterator >(); + test_copy_if, input_iterator >(); + test_copy_if, forward_iterator >(); + test_copy_if, bidirectional_iterator >(); + test_copy_if, random_access_iterator >(); + test_copy_if, int*>(); + + test_copy_if >(); + test_copy_if >(); + test_copy_if >(); + test_copy_if >(); + test_copy_if >(); + test_copy_if(); + + return true; +} + int main(int, char**) { - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test >(); - test >(); - test >(); - test >(); - test >(); - test(); - -// #if TEST_STD_VER > 17 -// static_assert(test_constexpr()); -// #endif + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp index 027dedc..179e4f1 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp @@ -19,23 +19,11 @@ #include "test_iterators.h" #include "user_defined_integral.h" -// #if TEST_STD_VER > 17 -// TEST_CONSTEXPR bool test_constexpr() { -// int ia[] = {1, 2, 3, 4, 5}; -// int ic[] = {6, 6, 6, 6, 6, 6, 6}; -// -// auto p = std::copy_n(std::begin(ia), 4, std::begin(ic)); -// return std::equal(std::begin(ic), p, std::begin(ia)) -// && std::all_of(p, std::end(ic), [](int a){return a == 6;}) -// ; -// } -// #endif - typedef UserDefinedIntegral UDI; template -void -test() +TEST_CONSTEXPR_CXX20 void +test_copy_n() { const unsigned N = 1000; int ia[N]; @@ -49,46 +37,54 @@ test() assert(ia[i] == ib[i]); } +TEST_CONSTEXPR_CXX20 bool +test() +{ + test_copy_n, output_iterator >(); + test_copy_n, input_iterator >(); + test_copy_n, forward_iterator >(); + test_copy_n, bidirectional_iterator >(); + test_copy_n, random_access_iterator >(); + test_copy_n, int*>(); + + test_copy_n, output_iterator >(); + test_copy_n, input_iterator >(); + test_copy_n, forward_iterator >(); + test_copy_n, bidirectional_iterator >(); + test_copy_n, random_access_iterator >(); + test_copy_n, int*>(); + + test_copy_n, output_iterator >(); + test_copy_n, input_iterator >(); + test_copy_n, forward_iterator >(); + test_copy_n, bidirectional_iterator >(); + test_copy_n, random_access_iterator >(); + test_copy_n, int*>(); + + test_copy_n, output_iterator >(); + test_copy_n, input_iterator >(); + test_copy_n, forward_iterator >(); + test_copy_n, bidirectional_iterator >(); + test_copy_n, random_access_iterator >(); + test_copy_n, int*>(); + + test_copy_n >(); + test_copy_n >(); + test_copy_n >(); + test_copy_n >(); + test_copy_n >(); + test_copy_n(); + + return true; +} + int main(int, char**) { - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test, output_iterator >(); - test, input_iterator >(); - test, forward_iterator >(); - test, bidirectional_iterator >(); - test, random_access_iterator >(); - test, int*>(); - - test >(); - test >(); - test >(); - test >(); - test >(); - test(); - -// #if TEST_STD_VER > 17 -// static_assert(test_constexpr()); -// #endif + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index a54787af..bc07e20 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -35,17 +35,17 @@ public: typedef It pointer; typedef typename std::iterator_traits::reference reference; - It base() const {return it_;} + TEST_CONSTEXPR_CXX14 It base() const {return it_;} - output_iterator () {} - explicit output_iterator(It it) : it_(it) {} + TEST_CONSTEXPR_CXX14 output_iterator () {} + explicit TEST_CONSTEXPR_CXX14 output_iterator(It it) : it_(it) {} template - output_iterator(const output_iterator& u) :it_(u.it_) {} + TEST_CONSTEXPR_CXX14 output_iterator(const output_iterator& u) :it_(u.it_) {} - reference operator*() const {return *it_;} + TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} - output_iterator& operator++() {++it_; return *this;} - output_iterator operator++(int) + TEST_CONSTEXPR_CXX14 output_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 output_iterator operator++(int) {output_iterator tmp(*this); ++(*this); return tmp;} template diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h index 74253a2..df480ab 100644 --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -125,6 +125,11 @@ # else # define TEST_THROW_SPEC(...) throw(__VA_ARGS__) # endif +# if TEST_STD_VER > 17 +# define TEST_CONSTEXPR_CXX20 constexpr +# else +# define TEST_CONSTEXPR_CXX20 +# endif #else #if defined(TEST_COMPILER_CLANG) # define TEST_ALIGNOF(...) _Alignof(__VA_ARGS__) @@ -134,6 +139,7 @@ #define TEST_ALIGNAS(...) __attribute__((__aligned__(__VA_ARGS__))) #define TEST_CONSTEXPR #define TEST_CONSTEXPR_CXX14 +#define TEST_CONSTEXPR_CXX20 #define TEST_NOEXCEPT throw() #define TEST_NOEXCEPT_FALSE #define TEST_NOEXCEPT_COND(...) diff --git a/libcxx/test/support/user_defined_integral.h b/libcxx/test/support/user_defined_integral.h index e3d5724..9f9ff45 100644 --- a/libcxx/test/support/user_defined_integral.h +++ b/libcxx/test/support/user_defined_integral.h @@ -8,12 +8,14 @@ #ifndef SUPPORT_USER_DEFINED_INTEGRAL_H #define SUPPORT_USER_DEFINED_INTEGRAL_H +#include "test_macros.h" + template struct UserDefinedIntegral { - UserDefinedIntegral() : value(0) {} - UserDefinedIntegral(T v) : value(v) {} - operator T() const { return value; } + TEST_CONSTEXPR_CXX14 UserDefinedIntegral() : value(0) {} + TEST_CONSTEXPR_CXX14 UserDefinedIntegral(T v) : value(v) {} + TEST_CONSTEXPR_CXX14 operator T() const { return value; } T value; }; -- 2.7.4