Boost logo

Boost :

Subject: Re: [boost] [type_traits] has_equal_to< std::vector<T> > always true_
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2012-07-15 03:10:54


Le 15/07/12 03:02, Lorenzo Caminiti a écrit :
> On Sat, Jul 7, 2012 at 1:34 AM, Frédéric Bron <frederic.bron_at_[hidden]> wrote:
>> 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.
Hi Lorenzo,

the trick is that every time you include
<boost/type_traits/has_equal_to.hpp> you need to include all the
specializations, otherwise you could have some parts of a program that
contains the specialization and not others. This is unfortunate, but as
the review of Boost.Conversion showed this is needed to maintain the
ODR. Note also that the inclusion of the file and the specialization
must be done only if the library is not conforming to the standard, and
we can expect that future libraries will conform to, so the inclusion
will not be requiered for the conforming versions.
>> 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>
> {};
I think bool need to be added here

template< typename T, class Alloc >
struct has_equal_to < std::vector<T, Alloc>, std::vector<T, Alloc>, bool > :
     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>
> >
> {};
I'm not sure this specialization is needed.
The convertibility to bool is already described with the first
specialization, as has_equal_to test for convertibility to the result,
not is_same.

> // 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?
>
>
You are missing the Allocator parameter. I'm not sure the following works.

BOOST_TEST((boost::has_equal_to<vi, vi, char>::value)); // ok: i == i

In any case, I don't think this should be a constraint.

Best,
Vicente


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