Opened 9 years ago

Closed 4 years ago

#9913 closed Bugs (obsolete)

boost::has_complement of enum class does not compile

Reported by: Nevin Liber <nevin@…> Owned by: bronf
Milestone: To Be Determined Component: type_traits
Version: Boost 1.55.0 Severity: Problem
Keywords: Cc: nevin@…

Description

(Also filed this as a gcc bug at http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60852)

This works under gcc 4.7.2 and clang 3.4, but fails to compile under gcc 4.9 RC1. enum class seems to be the only issue; plain enums work fine.

#include <boost/type_traits.hpp> #include <iostream>

enum class E {};

int main() { std::cout << boost::has_complement<E>() << std::endl; }

Using Boost 1.55 and g++ -std=c++11, we get:

In file included from /opt/local/include/boost/config.hpp:57:0,

from /opt/local/include/boost/type_traits/add_const.hpp:13, from /opt/local/include/boost/type_traits.hpp:13, from a.cpp:1:

/opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp: In instantiation of 'const bool boost::detail::has_complement_impl::operator_exists<E>::value': /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:173:4: required from 'const bool boost::detail::has_complement_impl::trait_impl1<E, boost::detail::has_complement_impl::dont_care, false>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:195:4: required from 'const bool boost::detail::has_complement_impl::trait_impl<E, boost::detail::has_complement_impl::dont_care>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:202:1: required from 'struct boost::has_complement<E>' a.cpp:7:41: required from here /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:152:56: error: no match for 'operator~' (operand type is 'E')

BOOST_STATIC_CONSTANT(bool, value = (sizeof(check(((BOOST_TT_TRAIT_OP make<Rhs>()),make<has_operator>())))==sizeof(::boost::type_traits::yes_type)));

/opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp: In instantiation of 'const bool boost::detail::has_complement_impl::operator_returns_void<E>::value': /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:173:4: required from 'const bool boost::detail::has_complement_impl::trait_impl1<E, boost::detail::has_complement_impl::dont_care, false>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:195:4: required from 'const bool boost::detail::has_complement_impl::trait_impl<E, boost::detail::has_complement_impl::dont_care>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:202:1: required from 'struct boost::has_complement<E>' a.cpp:7:41: required from here /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:89:102: error: no match for 'operator~' (operand type is 'E')

BOOST_STATIC_CONSTANT(bool, value = (sizeof(::boost::type_traits::yes_type)==sizeof(returns_void((BOOST_TT_TRAIT_OP make<Rhs>(),returns_void_t())))));

a.cpp: In function 'int main()': a.cpp:7:41: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

{ std::cout << boost::has_complement<E>() << std::endl; }

In file included from /opt/local/include/gcc49/c++/istream:39:0,

from /opt/local/include/gcc49/c++/sstream:38, from /opt/local/include/gcc49/c++/complex:45, from /opt/local/include/boost/type_traits/is_complex.hpp:12, from /opt/local/include/boost/type_traits.hpp:49, from a.cpp:1:

/opt/local/include/gcc49/c++/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = boost::has_complement<E>]'

operator<<(basic_ostream<_CharT, _Traits>&& os, const _Tp& x)

Attachments (1)

a.cpp (142 bytes ) - added by Nevin Liber <nevin@…> 9 years ago.
Reproducible test case

Download all attachments as: .zip

Change History (7)

by Nevin Liber <nevin@…>, 9 years ago

Attachment: a.cpp added

Reproducible test case

comment:1 by Nevin Liber <nevin@…>, 9 years ago

Discussion on Stack Overflow seems to indicate the bug is in Boost: <http://stackoverflow.com/questions/23108590/is-this-valid-c11>.

comment:2 by Nevin Liber <nevin@…>, 9 years ago

Bug filed against clang current behavior <http://llvm.org/bugs/show_bug.cgi?id=19452>.

comment:3 by John Maddock, 8 years ago

Owner: changed from John Maddock to bronf

Confirmed that this is a problem with our code - it seems that class enum's are unique in not accepting these operator overloads. Given that, I'm actually not sure if it's even possible to implement has*operator for class enum types :-(

Reassigning to the author of those files in the hopes of a fix....

comment:4 by Nevin Liber <nevin@…>, 8 years ago

Here is my C++11 only version of has_complement:

    namespace detail
    {   
        namespace has_complement_impl
        {   
            struct dont_care {}; 

            template<typename Rhs, typename Ret>
            class has_complement_trait
            {   
                template<typename Hs, 
                         typename Et = decltype(~std::declval<Hs>()),
                         typename = typename std::enable_if<std::is_same<dont_care, Ret>::value ||
                                                            std::is_convertible<Et, Ret>::value>::type>
                static true_type has_complement_operator(int);

                template<typename>
                static false_type has_complement_operator(...);

            public:
                using type = decltype(has_complement_operator<Rhs>(0));
            };  
        }; // has_complement_impl namespace
    } // detail namespace

    template<typename Rhs, typename Ret = detail::has_complement_impl::dont_care>
    struct has_complement
    : detail::has_complement_impl::has_complement_trait<Rhs, Ret>::type
    {}; 

comment:5 by John Maddock, 8 years ago

Thanks that's really neat!

Hopefully Frederic Bron will take this up as he's much more familiar with the internals of these traits than I am.

Note that the issue effects not just the unary operators, but all the binary operators such as has_plus etc suffer the same issue.

We also need to figure out what config macros will determine when the above approach can be used - BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS and BOOST_NO_CXX11_DECLTYPE certainly, possibly BOOST_NO_SFINAE_EXPR as well.

comment:6 by John Maddock, 4 years ago

Resolution: obsolete
Status: newclosed
Note: See TracTickets for help on using tickets.