Boost logo

Boost :

Subject: Re: [boost] [type_traits] has_equal_to< std::vector<T> > always true_
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2012-07-14 21:02:57


On Sat, Jul 7, 2012 at 1:34 AM, Frédéric Bron <frederic.bron_at_[hidden]> wrote:
> Hi Lorenzo,
>
> Thanks for pushing this topic. Sorry to only replying now but it is
> hard to find some free time with 3 little children!

No problem. I also don't have much time to work on this but let's
continue to discuss how it should be implemented then I'll put it in a
release.

> I have looked a bit at the standard (ISO/IEC 14882, 2011). The
> relevant text is: 23.2.1, Table 96, 25.2.11.
>
> This is what I have found:
>
> if a and b are container<T> and t1 and t2 are T:
> - a==b: requires t1==t2 returning convertible to bool
> - a!=b: requires a==b
> - a<b: calls std::lexicographical_compare -> requires t1<t2 returning
> convertible to bool
> . a>b: requires b<a
> . a<=b: requires !(b<a)
> . a>=b: requires !(a<b)
>
> So in short: a==b and a!=b require t1==t2 and a<b, a>b, a<=b, a>=b
> require t1<t2 returning convertible to bool.
>
>> namespace std { // fwd decl so no need to include STL
>> template< typename T, class Alloc > class vector;
>> } // namespace std
>
> Concerning your proposal to forward declare the containers, it is
> halas not allowed by the standard (17.6.4.2.1 Namespace std):
> "The behavior of a C++ program is undefined if it adds declarations or
> definitions to namespace std or to a namespace within namespace std
> unless otherwise specified."

:( Then all vector specializations go in a header
boost/type_traits/std/vector.hpp (which will include <vector>), same
for list, etc.

> I imagine easily that it should behave as intended but it seems
> possible for an implementation to not like it.
>
>> template< typename T, class LhsAlloc, class RhsAlloc, typename Ret >
>> struct has_equal_to < std::vector<T, LhsAlloc >, std::vector<T, RhsAlloc >, Ret > : has_equal_to<T, T, Ret>
>> {};
>
> The standard defines the operators only for identical allocators.
> operator== always returns bool and has_equal_to should return
> convertible to bool. This should be reflected in the declaration.

OK, how about this?
1) identical LHS and RHS containers (same T, Alloc, etc).
2) If no Ret then require bool, otherwise require convertible to bool.

// In header: boost/type_traits/std/vector.hpp
#include <boost/type_traits/has_equal_to.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/mpl/and.hpp>
#include <vector>

// NOTE: Cannot fwd decl STL types (otherwise undefined behaviour).
// From standard, let a and b be STL container<T>, and x and y be T, then:
// * a == b defined requiring x == y convertible to bool
// * a != b defined requiring !(a == b)
// * a < b defined as std::lexicographical_compare that requires x < y
// convertible to boo
// * a > b defined requiring x > y
// * a <= b defined requiring !(a > b)
// * a >= b defined requiring !(a < b)

namespace boost {

template< typename T, class Alloc >
struct has_equal_to < std::vector<T, Alloc>, std::vector<T, Alloc> > :
    has_equal_to<T, T, bool>
{};

template< typename T, class Alloc, typename Ret >
struct has_equal_to < std::vector<T, Alloc>, std::vector<T, Alloc>, Ret > :
    mpl::and_<
          has_equal_to<T, T, bool>
        , is_convertible<Ret, bool>
>
{};

// specializations for more STL containers here...

} // namespace

// -- header ends --

// test program

#include <boost/detail/lightweight_test.hpp>
#include <iostream>

struct xyz {}; // this type has no operator==

int main ( void )
{
    typedef std::vector<int> vi;
    typedef std::vector<xyz> vx;

    // vi i;
    // vx x;
    // i == i; // ok
    // x == x; // error
    // x == i; // error
    // i == x; // error

    // 1 tparam
    BOOST_TEST((boost::has_equal_to<vi>::value)); // ok: i == i
    BOOST_TEST((!boost::has_equal_to<vx>::value)); // error: x == x
    // 2 tparams
    BOOST_TEST((boost::has_equal_to<vi, vi>::value)); // ok: i == i
    BOOST_TEST((!boost::has_equal_to<vx, vx>::value)); // error: x == x
    BOOST_TEST((!boost::has_equal_to<vx, vi>::value)); // error: x == i
    BOOST_TEST((!boost::has_equal_to<vi, vx>::value)); // error: i == x
    // 3 tparams
    BOOST_TEST((boost::has_equal_to<vi, vi, char>::value)); // ok: i == i
    BOOST_TEST((!boost::has_equal_to<vx, vx, char>::value)); // error: x == x
    BOOST_TEST((!boost::has_equal_to<vx, vi, char>::value)); // error: x == i
    BOOST_TEST((!boost::has_equal_to<vi, vx, char>::value)); // error: i == x

    return boost::report_errors();
}

Also, am I missing any relevant test?

Thanks.
--Lorenzo


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk