Re: [boost] [contract] extra type requirements for contracts

On Thu, 22 Sep 2011 08:03:09 lcaminiti wrote:
For example, the following code asserts back() == value only when can_call_equal<T>::value is true. However, is there a better way to do this that does not require the extra function call to post1?
Unless I'm missing something, you should be able to replace the post1() calls with assert(boost::can_call_equal<T>::value && std::clog << "actual assertion\n" == std::clog && back() == value || std::clog << "trivial assertion\n" == std::clog);

On Thu, Sep 22, 2011 at 10:25 PM, Brent Spillner <spillner@acm.org> wrote:
For example, the following code asserts back() == value only when can_call_equal<T>::value is true. However, is there a better way to do
On Thu, 22 Sep 2011 08:03:09 lcaminiti wrote: this
that does not require the extra function call to post1?
Unless I'm missing something, you should be able to replace the post1() calls with
assert(boost::can_call_equal<T>::value && std::clog << "actual assertion\n" == std::clog && back() == value || std::clog << "trivial assertion\n" == std::clog);
Unfortunately, the compiler can't do a "syntactic short-circuit" when !can_call_equal<T>::value and simply skip over the "back() == value" expression; "back() == value" still needs to be a valid expression, i.e., if an appropriate operator== isn't found, you'll still get a compiler error :( Compare to false && (pretty-sure*the==compiler&wont^like%this) ...at least most of the time, anyway... - Jeff

On Fri, Sep 23, 2011 at 5:25 AM, Brent Spillner <spillner@acm.org> wrote:
Unless I'm missing something, you should be able to replace the
Oof, I sure was... that's what I get for posting at 2 in the morning. I can't see any way around an extra function, but I would probably encapsulate it with something like template < class T, class U > typename boost::enable_if_c< can_call_equal<T>::value, bool >::type equality_test(const T &t, const U &u) { return t == u; } bool equality_test(...) { return true; } to avoid littering the generated class with a bunch of one-off postN()s.

On Thu, 22 Sep 2011 10:30:14 lcaminiti wrote:
I think this can be achieved with my previous "option 2" suggestion:
namespace dummy { template< typename L, typename R> bool operator== ( L const&, R const& ) { return true; } }
postcondition( using dummy::operator==, back() == value )
This will fail if L has a private (or protected) operator==.

Brent Spillner wrote:
On Thu, 22 Sep 2011 10:30:14 lcaminiti wrote:
I think this can be achieved with my previous "option 2" suggestion:
namespace dummy { template< typename L, typename R> bool operator== ( L const&, R const& ) { return true; } }
postcondition( using dummy::operator==, back() == value )
This will fail if L has a private (or protected) operator==.
Let me understand your point a bit better. I think you mean something like this: #include <boost/type_traits/can_call_equal.hpp> #include <vector> #include <iostream> #include <cassert> namespace dummy { template< typename L, typename R > bool operator== ( L const& left, R const& right ) { std::clog << "dummy ==\n"; return true; } } template< typename T > struct vect { void push_back ( T const& value ) { v_.push_back(value); using dummy::operator==; assert( back() == value ); } T const& back ( ) const { return v_.back(); } private: std::vector<T> v_; }; struct val { private: bool operator== ( val const& right ) const { std::clog << "val ==\n"; return true; } }; int main ( ) { vect<val> v; v.push_back(val()); // error 1 std::cout << boost::can_call_equal<val>::value << std::endl; // error 2 return 0; }; In this case T = val has an operator== which is private. This causes both the methods (1) using dummy::operator== and (2) the traits requirement can_call_equal<val> to fail :( Ideally, can_call_equal<val>::value will return false instead of generating a compiler-error when val::operator== is private or protected. A part from such an (impossible?) improvement to can_call_equal, I have no solution for this issue. I can document it and at the end the library users are responsible to program contracts with assertion requirements that can be checked within C++ (and can_call_equal<val> when val has a private operator== cannot be checked so it's simply a ill-formed assertion requirement). What do you think? --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/boost-contract-extra-type-requirements-fo... Sent from the Boost - Dev mailing list archive at Nabble.com.

Brent Spillner wrote:
On Fri, Sep 23, 2011 at 5:25 AM, Brent Spillner <spillner@acm.org> wrote:
Unless I'm missing something, you should be able to replace the
Oof, I sure was... that's what I get for posting at 2 in the morning.
I can't see any way around an extra function, but I would probably encapsulate it with something like
template < class T, class U > typename boost::enable_if_c< can_call_equal<T>::value, bool >::type equality_test(const T &t, const U &u) { return t == u; }
bool equality_test(...) { return true; }
to avoid littering the generated class with a bunch of one-off postN()s.
Using equality_test works for back() == value. However, in general the assertion can be as complex as you wish so I need to introduce general extra functions postN (littering the user class, my library already litters the user class quite a bit with a number of extra functions, about +5 functions for every member function!! to check pre/postconditions, subcontract, and copy old-ofs). The extra postN functions are only introduced when requires is used on an assertion, so you can chose between generality of the contracts and the cost of the extra functions (to compile and call). A more complex example: postcondition( auto result = return, result == x + y, requires has_equal_to<T>::value && has_plus<T>::value ) I can't use equality_test here. (This could work with T = int, T = std::string, etc.) You can construct an arbitrary complex example: struct airplane { bool started ( ) const { ... } bool flying () const { ... } }; struct car { bool started ( ) const { ... } bool driving () const { ... } }; postcondition( machine.started() && machine.flying(), requires is_airplane<Machine>, machine.started() && machine.driving(), requires is_car<Machine> ) OK this is a silly example, intentionally complex, but it's just to illustrate that equality_test is not generic enough and it won't work in this case. Thanks. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/boost-contract-extra-type-requirements-fo... Sent from the Boost - Dev mailing list archive at Nabble.com.
participants (3)
-
Brent Spillner
-
Jeffrey Lee Hellrung, Jr.
-
lcaminiti