
On Sun, Jul 15, 2012 at 3:10 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> 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