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-15 10:14:23


On Sun, Jul 15, 2012 at 3:10 AM, Vicente J. Botet Escriba
<vicente.botet_at_[hidden]> wrote:
> 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

Then the specializations have to go into
boost/type_traits/has_equal_to.hpp which will have to include <vector>
:(

> 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 don't think this is true... the specializations will always be
needed unless future standards remove operator== (<, etc) from the
overloaded set using SFINAE when T doesn't have an operator== (<,
etc). But based on C++03 and C++11, the STL defines operator== and the
has_equal_to (has_less_than, etc) specializations are needed.

>> 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>
> {};

Not IMO because then only has_equal_to<vector<int>, vector<int>, bool>
will work. As a user I want to use has_equal_to<vector<int>,
vector<int> > without the return type and for it to be smart enough to
use the correct result type, which is bool in this case. So I think
users will expect this specialization:

 template< typename T, class Alloc >
 struct has_equal_to < std::vector<T, Alloc>, std::vector<T, Alloc> /*
no bool here */ > :
      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.

The allocator parameter for both LHS and RHS always has to be the
same... is it important to test using not the default allocator? Maybe
I should test with different allocator paramters and make sure it
returns false - I'll add these tests.

> 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.

Thanks a lot!
--Lorenzo


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