From 84f9b6da6822aa1f39b5f7367b8d285d9038ba26 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Tue, 13 Feb 2018 19:18:12 +0000 Subject: [PATCH] binary operators: add revised workaounds for gcc-4.7 and 4.8 --- .../detail/has_binary_operator.hpp | 1 + .../type_traits/detail/is_likely_lambda.hpp | 94 +++++++++++++++++++ include/boost/type_traits/has_equal_to.hpp | 2 +- include/boost/type_traits/has_greater.hpp | 2 +- .../boost/type_traits/has_greater_equal.hpp | 2 +- include/boost/type_traits/has_less.hpp | 2 +- include/boost/type_traits/has_less_equal.hpp | 2 +- .../boost/type_traits/has_not_equal_to.hpp | 2 +- test/has_equal_to_test.cpp | 9 ++ test/has_greater_equal_test.cpp | 9 ++ test/has_greater_test.cpp | 9 ++ test/has_less_equal_test.cpp | 9 ++ test/has_less_test.cpp | 9 ++ test/has_not_equal_to_test.cpp | 9 ++ 14 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 include/boost/type_traits/detail/is_likely_lambda.hpp diff --git a/include/boost/type_traits/detail/has_binary_operator.hpp b/include/boost/type_traits/detail/has_binary_operator.hpp index 8fb552b..ec6e52e 100644 --- a/include/boost/type_traits/detail/has_binary_operator.hpp +++ b/include/boost/type_traits/detail/has_binary_operator.hpp @@ -95,6 +95,7 @@ namespace boost #include #include #include +#include namespace boost { namespace detail { diff --git a/include/boost/type_traits/detail/is_likely_lambda.hpp b/include/boost/type_traits/detail/is_likely_lambda.hpp new file mode 100644 index 0000000..a5cc19c --- /dev/null +++ b/include/boost/type_traits/detail/is_likely_lambda.hpp @@ -0,0 +1,94 @@ +/* Copyright 2017 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org/libs/poly_collection for library home page. + */ + +#ifndef BOOST_TT_DETAIL_IS_LIKELY_STATELESS_LAMBDA_HPP +#define BOOST_TT_DETAIL_IS_LIKELY_STATELESS_LAMBDA_HPP + +#if defined(_MSC_VER) +#pragma once +#endif + +#include +#include + +#if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) +// +// We don't need or use this, just define a dummy class: +// +namespace boost{ namespace type_traits_detail{ + +template +struct is_likely_stateless_lambda : public false_type {}; + +}} + +#elif !defined(BOOST_NO_CXX11_LAMBDAS) && !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +#include +#include + +namespace boost{ + +namespace type_traits_detail{ + +/* Stateless lambda expressions have one (and only one) call operator and are + * convertible to a function pointer with the same signature. Non-lambda types + * could satisfy this too, hence the "likely" qualifier. + */ + +template +struct has_one_operator_call_helper +{ + template static boost::true_type test(decltype(&Q::operator())*); + template static boost::false_type test(...); + + using type=decltype(test(nullptr)); +}; + +template +using has_one_operator_call=typename has_one_operator_call_helper::type; + +template +struct equivalent_function_pointer +{ + template + static auto helper(R (Q::*)(Args...)const)->R(*)(Args...); + template + static auto helper(R (Q::*)(Args...))->R(*)(Args...); + + using type=decltype(helper(&T::operator())); +}; + +template +struct is_likely_stateless_lambda : false_type{}; + +template +struct is_likely_stateless_lambda< + T, + typename boost::enable_if_c::value>::type> : + boost::is_convertible::type +>{}; + +} /* namespace type_traits_detail */ + +} /* namespace boost */ + +#else +// +// Can't implement this: +// +namespace boost{ namespace type_traits_detail{ + +template +struct is_likely_stateless_lambda : public false_type {}; + +}} + +#endif +#endif + diff --git a/include/boost/type_traits/has_equal_to.hpp b/include/boost/type_traits/has_equal_to.hpp index fc672d4..3405d34 100644 --- a/include/boost/type_traits/has_equal_to.hpp +++ b/include/boost/type_traits/has_equal_to.hpp @@ -38,7 +38,7 @@ )\ ) || \ (\ - ::boost::is_class::value && ::boost::is_convertible::value\ + ::boost::type_traits_detail::is_likely_stateless_lambda::value\ )\ ) diff --git a/include/boost/type_traits/has_greater.hpp b/include/boost/type_traits/has_greater.hpp index 39be51e..1a9fda6 100644 --- a/include/boost/type_traits/has_greater.hpp +++ b/include/boost/type_traits/has_greater.hpp @@ -38,7 +38,7 @@ )\ ) || \ (\ - ::boost::is_class::value && ::boost::is_convertible::value\ + ::boost::type_traits_detail::is_likely_stateless_lambda::value\ )\ ) diff --git a/include/boost/type_traits/has_greater_equal.hpp b/include/boost/type_traits/has_greater_equal.hpp index 09b42b9..c87f063 100644 --- a/include/boost/type_traits/has_greater_equal.hpp +++ b/include/boost/type_traits/has_greater_equal.hpp @@ -38,7 +38,7 @@ )\ ) || \ (\ - ::boost::is_class::value && ::boost::is_convertible::value\ + ::boost::type_traits_detail::is_likely_stateless_lambda::value\ )\ ) diff --git a/include/boost/type_traits/has_less.hpp b/include/boost/type_traits/has_less.hpp index 2a33291..1326a18 100644 --- a/include/boost/type_traits/has_less.hpp +++ b/include/boost/type_traits/has_less.hpp @@ -38,7 +38,7 @@ )\ ) || \ (\ - ::boost::is_class::value && ::boost::is_convertible::value\ + ::boost::type_traits_detail::is_likely_stateless_lambda::value\ )\ ) diff --git a/include/boost/type_traits/has_less_equal.hpp b/include/boost/type_traits/has_less_equal.hpp index 4f38a1b..607b71c 100644 --- a/include/boost/type_traits/has_less_equal.hpp +++ b/include/boost/type_traits/has_less_equal.hpp @@ -38,7 +38,7 @@ )\ ) || \ (\ - ::boost::is_class::value && ::boost::is_convertible::value\ + ::boost::type_traits_detail::is_likely_stateless_lambda::value\ )\ ) diff --git a/include/boost/type_traits/has_not_equal_to.hpp b/include/boost/type_traits/has_not_equal_to.hpp index 82060e7..5f2c39a 100644 --- a/include/boost/type_traits/has_not_equal_to.hpp +++ b/include/boost/type_traits/has_not_equal_to.hpp @@ -38,7 +38,7 @@ )\ ) || \ (\ - ::boost::is_class::value && ::boost::is_convertible::value\ + ::boost::type_traits_detail::is_likely_stateless_lambda::value\ )\ ) diff --git a/test/has_equal_to_test.cpp b/test/has_equal_to_test.cpp index 62d54ee..9955bf3 100644 --- a/test/has_equal_to_test.cpp +++ b/test/has_equal_to_test.cpp @@ -222,15 +222,24 @@ void specific() { #if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) // There are some things that pass that wouldn't otherwise do so: auto f = []() {}; + auto f2 = [](double)->int { return 2; }; #ifndef BOOST_MSVC TEST_TR(decltype(f), bool, true); + TEST_TR(decltype(f2), bool, true); #else TEST_TR(decltype(f), bool, false); + TEST_TR(decltype(f2), bool, false); #endif + (void)f; + (void)f2; #elif !defined(BOOST_NO_CXX11_LAMBDAS) auto f = []() {}; + auto f2 = [](double)->int { return 2; }; BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f)>::value), 0); + BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f2)>::value), 0); + (void)f; + (void)f2; #endif } diff --git a/test/has_greater_equal_test.cpp b/test/has_greater_equal_test.cpp index c0c96fa..fd7a334 100644 --- a/test/has_greater_equal_test.cpp +++ b/test/has_greater_equal_test.cpp @@ -222,15 +222,24 @@ void specific() { #if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) // There are some things that pass that wouldn't otherwise do so: auto f = []() {}; + auto f2 = [](double)->int { return 2; }; #ifndef BOOST_MSVC TEST_TR(decltype(f), bool, true); + TEST_TR(decltype(f2), bool, true); #else TEST_TR(decltype(f), bool, false); + TEST_TR(decltype(f2), bool, false); #endif + (void)f; + (void)f2; #elif !defined(BOOST_NO_CXX11_LAMBDAS) auto f = []() {}; + auto f2 = [](double)->int { return 2; }; BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f)>::value), 0); + BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f2)>::value), 0); + (void)f; + (void)f2; #endif } diff --git a/test/has_greater_test.cpp b/test/has_greater_test.cpp index 6576f39..17a76f7 100644 --- a/test/has_greater_test.cpp +++ b/test/has_greater_test.cpp @@ -222,15 +222,24 @@ void specific() { #if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) // There are some things that pass that wouldn't otherwise do so: auto f = []() {}; + auto f2 = [](double)->int { return 2; }; #ifndef BOOST_MSVC TEST_TR(decltype(f), bool, true); + TEST_TR(decltype(f2), bool, true); #else TEST_TR(decltype(f), bool, false); + TEST_TR(decltype(f2), bool, false); #endif + (void)f; + (void)f2; #elif !defined(BOOST_NO_CXX11_LAMBDAS) auto f = []() {}; + auto f2 = [](double)->int { return 2; }; BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f)>::value), 0); + BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f2)>::value), 0); + (void)f; + (void)f2; #endif } diff --git a/test/has_less_equal_test.cpp b/test/has_less_equal_test.cpp index 7cf46b1..3d57574 100644 --- a/test/has_less_equal_test.cpp +++ b/test/has_less_equal_test.cpp @@ -222,15 +222,24 @@ void specific() { #if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) // There are some things that pass that wouldn't otherwise do so: auto f = []() {}; + auto f2 = [](double)->int { return 2; }; #ifndef BOOST_MSVC TEST_TR(decltype(f), bool, true); + TEST_TR(decltype(f2), bool, true); #else TEST_TR(decltype(f), bool, false); + TEST_TR(decltype(f2), bool, false); #endif + (void)f; + (void)f2; #elif !defined(BOOST_NO_CXX11_LAMBDAS) auto f = []() {}; + auto f2 = [](double)->int { return 2; }; BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f)>::value), 0); + BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f2)>::value), 0); + (void)f; + (void)f2; #endif } diff --git a/test/has_less_test.cpp b/test/has_less_test.cpp index 64065a0..3358bf9 100644 --- a/test/has_less_test.cpp +++ b/test/has_less_test.cpp @@ -222,15 +222,24 @@ void specific() { #if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) // There are some things that pass that wouldn't otherwise do so: auto f = []() {}; + auto f2 = [](double)->int { return 2; }; #ifndef BOOST_MSVC TEST_TR(decltype(f), bool, true); + TEST_TR(decltype(f2), bool, true); #else TEST_TR(decltype(f), bool, false); + TEST_TR(decltype(f2), bool, false); #endif + (void)f; + (void)f2; #elif !defined(BOOST_NO_CXX11_LAMBDAS) auto f = []() {}; + auto f2 = [](double)->int { return 2; }; BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f)>::value), 0); + BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f2)>::value), 0); + (void)f; + (void)f2; #endif } diff --git a/test/has_not_equal_to_test.cpp b/test/has_not_equal_to_test.cpp index ce6b880..c0e027a 100644 --- a/test/has_not_equal_to_test.cpp +++ b/test/has_not_equal_to_test.cpp @@ -222,15 +222,24 @@ void specific() { #if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) // There are some things that pass that wouldn't otherwise do so: auto f = []() {}; + auto f2 = [](double)->int { return 2; }; #ifndef BOOST_MSVC TEST_TR(decltype(f), bool, true); + TEST_TR(decltype(f2), bool, true); #else TEST_TR(decltype(f), bool, false); + TEST_TR(decltype(f2), bool, false); #endif + (void)f; + (void)f2; #elif !defined(BOOST_NO_CXX11_LAMBDAS) auto f = []() {}; + auto f2 = [](double)->int { return 2; }; BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f)>::value), 0); + BOOST_CHECK_INTEGRAL_CONSTANT((::boost::BOOST_TT_TRAIT_NAME< decltype(f2)>::value), 0); + (void)f; + (void)f2; #endif }