From b4881265fbe2100211a7ffb734ce2aaa0d009835 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 20 Mar 2015 16:32:43 +0200 Subject: [PATCH 1/4] Add test for a function+bind regression reported by Marcel Raad --- test/Jamfile.v2 | 1 + test/bind_function2_test.cpp | 118 +++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 test/bind_function2_test.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1c6a707..85b381c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -47,4 +47,5 @@ test-suite "bind" [ run bind_eq3_test.cpp ] [ run protect_test.cpp ] [ run mem_fn_unary_addr_test.cpp ] + [ run bind_function2_test.cpp ] ; diff --git a/test/bind_function2_test.cpp b/test/bind_function2_test.cpp new file mode 100644 index 0000000..d1a7d07 --- /dev/null +++ b/test/bind_function2_test.cpp @@ -0,0 +1,118 @@ +#include + +// +// bind_function2_test.cpp - regression test +// +// Copyright (c) 2015 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include +#include + +// + +void fv1( int & a ) +{ + a = 17041; +} + +void fv2( int & a, int b ) +{ + a = b; +} + +void fv3( int & a, int b, int c ) +{ + a = b + c; +} + +void fv4( int & a, int b, int c, int d ) +{ + a = b + c + d; +} + +void fv5( int & a, int b, int c, int d, int e ) +{ + a = b + c + d + e; +} + +void fv6( int & a, int b, int c, int d, int e, int f ) +{ + a = b + c + d + e + f; +} + +void fv7( int & a, int b, int c, int d, int e, int f, int g ) +{ + a = b + c + d + e + f + g; +} + +void fv8( int & a, int b, int c, int d, int e, int f, int g, int h ) +{ + a = b + c + d + e + f + g + h; +} + +void fv9( int & a, int b, int c, int d, int e, int f, int g, int h, int i ) +{ + a = b + c + d + e + f + g + h + i; +} + +void function_test() +{ + int x = 0; + + { + boost::function fw1 = boost::bind( fv1, _1 ); + fw1( x ); BOOST_TEST( x == 17041 ); + } + + { + boost::function fw2 = boost::bind( fv2, _1, _2 ); + fw2( x, 1 ); BOOST_TEST( x == 1 ); + } + + { + boost::function fw3 = boost::bind( fv3, _1, _2, _3 ); + fw3( x, 1, 2 ); BOOST_TEST( x == 1+2 ); + } + + { + boost::function fw4 = boost::bind( fv4, _1, _2, _3, _4 ); + fw4( x, 1, 2, 3 ); BOOST_TEST( x == 1+2+3 ); + } + + { + boost::function fw5 = boost::bind( fv5, _1, _2, _3, _4, _5 ); + fw5( x, 1, 2, 3, 4 ); BOOST_TEST( x == 1+2+3+4 ); + } + + { + boost::function fw6 = boost::bind( fv6, _1, _2, _3, _4, _5, _6 ); + fw6( x, 1, 2, 3, 4, 5 ); BOOST_TEST( x == 1+2+3+4+5 ); + } + + { + boost::function fw7 = boost::bind( fv7, _1, _2, _3, _4, _5, _6, _7 ); + fw7( x, 1, 2, 3, 4, 5, 6 ); BOOST_TEST( x == 1+2+3+4+5+6 ); + } + + { + boost::function fw8 = boost::bind( fv8, _1, _2, _3, _4, _5, _6, _7, _8 ); + fw8( x, 1, 2, 3, 4, 5, 6, 7 ); BOOST_TEST( x == 1+2+3+4+5+6+7 ); + } + + { + boost::function fw9 = boost::bind( fv9, _1, _2, _3, _4, _5, _6, _7, _8, _9 ); + fw9( x, 1, 2, 3, 4, 5, 6, 7, 8 ); BOOST_TEST( x == 1+2+3+4+5+6+7+8 ); + } +} + +int main() +{ + function_test(); + return boost::report_errors(); +} From 46c414606c63c22eedd622746a989497f8f59fe7 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 20 Mar 2015 16:43:54 +0200 Subject: [PATCH 2/4] Add forwarding test. --- test/Jamfile.v2 | 1 + test/bind_function2_test.cpp | 2 +- test/bind_fwd_test.cpp | 250 +++++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 test/bind_fwd_test.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 85b381c..39845d9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -48,4 +48,5 @@ test-suite "bind" [ run protect_test.cpp ] [ run mem_fn_unary_addr_test.cpp ] [ run bind_function2_test.cpp ] + [ run bind_fwd_test.cpp ] ; diff --git a/test/bind_function2_test.cpp b/test/bind_function2_test.cpp index d1a7d07..f991248 100644 --- a/test/bind_function2_test.cpp +++ b/test/bind_function2_test.cpp @@ -6,7 +6,7 @@ // Copyright (c) 2015 Peter Dimov // // Distributed under the Boost Software License, Version 1.0. -// See accompanying file LICENSE_1_0.txt or copy at +// See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // diff --git a/test/bind_fwd_test.cpp b/test/bind_fwd_test.cpp new file mode 100644 index 0000000..92bd3b1 --- /dev/null +++ b/test/bind_fwd_test.cpp @@ -0,0 +1,250 @@ +#include + +// +// bind_fwd_test.cpp - forwarding test +// +// Copyright (c) 2015 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +// + +void fv1( int & a ) +{ + a = 1; +} + +void fv2( int & a, int & b ) +{ + a = 1; + b = 2; +} + +void fv3( int & a, int & b, int & c ) +{ + a = 1; + b = 2; + c = 3; +} + +void fv4( int & a, int & b, int & c, int & d ) +{ + a = 1; + b = 2; + c = 3; + d = 4; +} + +void fv5( int & a, int & b, int & c, int & d, int & e ) +{ + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; +} + +void fv6( int & a, int & b, int & c, int & d, int & e, int & f ) +{ + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; + f = 6; +} + +void fv7( int & a, int & b, int & c, int & d, int & e, int & f, int & g ) +{ + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; + f = 6; + g = 7; +} + +void fv8( int & a, int & b, int & c, int & d, int & e, int & f, int & g, int & h ) +{ + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; + f = 6; + g = 7; + h = 8; +} + +void fv9( int & a, int & b, int & c, int & d, int & e, int & f, int & g, int & h, int & i ) +{ + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; + f = 6; + g = 7; + h = 8; + i = 9; +} + +void test() +{ + { + int a = 0; + + boost::bind( fv1, _1 )( a ); + + BOOST_TEST( a == 1 ); + } + + { + int a = 0; + int b = 0; + + boost::bind( fv2, _1, _2 )( a, b ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + } + + { + int a = 0; + int b = 0; + int c = 0; + + boost::bind( fv3, _1, _2, _3 )( a, b, c ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + BOOST_TEST( c == 3 ); + } + + { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + + boost::bind( fv4, _1, _2, _3, _4 )( a, b, c, d ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + BOOST_TEST( c == 3 ); + BOOST_TEST( d == 4 ); + } + + { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + + boost::bind( fv5, _1, _2, _3, _4, _5 )( a, b, c, d, e ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + BOOST_TEST( c == 3 ); + BOOST_TEST( d == 4 ); + BOOST_TEST( e == 5 ); + } + + { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + + boost::bind( fv6, _1, _2, _3, _4, _5, _6 )( a, b, c, d, e, f ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + BOOST_TEST( c == 3 ); + BOOST_TEST( d == 4 ); + BOOST_TEST( e == 5 ); + BOOST_TEST( f == 6 ); + } + + { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + + boost::bind( fv7, _1, _2, _3, _4, _5, _6, _7 )( a, b, c, d, e, f, g ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + BOOST_TEST( c == 3 ); + BOOST_TEST( d == 4 ); + BOOST_TEST( e == 5 ); + BOOST_TEST( f == 6 ); + BOOST_TEST( g == 7 ); + } + + { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + + boost::bind( fv8, _1, _2, _3, _4, _5, _6, _7, _8 )( a, b, c, d, e, f, g, h ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + BOOST_TEST( c == 3 ); + BOOST_TEST( d == 4 ); + BOOST_TEST( e == 5 ); + BOOST_TEST( f == 6 ); + BOOST_TEST( g == 7 ); + BOOST_TEST( h == 8 ); + } + + { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + + boost::bind( fv9, _1, _2, _3, _4, _5, _6, _7, _8, _9 )( a, b, c, d, e, f, g, h, i ); + + BOOST_TEST( a == 1 ); + BOOST_TEST( b == 2 ); + BOOST_TEST( c == 3 ); + BOOST_TEST( d == 4 ); + BOOST_TEST( e == 5 ); + BOOST_TEST( f == 6 ); + BOOST_TEST( g == 7 ); + BOOST_TEST( h == 8 ); + BOOST_TEST( i == 9 ); + } +} + +int main() +{ + test(); + return boost::report_errors(); +} From 8e54850ab6ff7a2cb2d90934785760ef5600060e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 20 Mar 2015 16:53:30 +0200 Subject: [PATCH 3/4] Add forwarding test for 2 arguments. --- test/Jamfile.v2 | 1 + test/bind_fwd2_test.cpp | 121 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 test/bind_fwd2_test.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 39845d9..52e57cd 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -49,4 +49,5 @@ test-suite "bind" [ run mem_fn_unary_addr_test.cpp ] [ run bind_function2_test.cpp ] [ run bind_fwd_test.cpp ] + [ run bind_fwd2_test.cpp ] ; diff --git a/test/bind_fwd2_test.cpp b/test/bind_fwd2_test.cpp new file mode 100644 index 0000000..5b7bf9c --- /dev/null +++ b/test/bind_fwd2_test.cpp @@ -0,0 +1,121 @@ +#include + +// +// bind_fwd2_test.cpp - forwarding test for 2 arguments +// +// Copyright (c) 2015 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +// + +int fv1( int const & a ) +{ + return a; +} + +void fv2_1( int & a, int const & b ) +{ + a = b; +} + +void fv2_2( int const & a, int & b ) +{ + b = a; +} + +int fv2_3( int const & a, int const & b ) +{ + return a+b; +} + +void test() +{ + { + int const a = 1; + int r = boost::bind( fv1, _1 )( a ); + BOOST_TEST( r == 1 ); + } + + { + int r = boost::bind( fv1, _1 )( 1 ); + BOOST_TEST( r == 1 ); + } + + { + int a = 1; + int const b = 2; + + boost::bind( fv2_1, _1, _2 )( a, b ); + + BOOST_TEST( a == 2 ); + } + + { + int a = 1; + + boost::bind( fv2_1, _1, _2 )( a, 2 ); + + BOOST_TEST( a == 2 ); + } + + { + int const a = 1; + int b = 2; + + boost::bind( fv2_2, _1, _2 )( a, b ); + + BOOST_TEST( b == 1 ); + } + + { + int b = 2; + + boost::bind( fv2_2, _1, _2 )( 1, b ); + + BOOST_TEST( b == 1 ); + } + + { + int const a = 1; + int const b = 2; + + int r = boost::bind( fv2_3, _1, _2 )( a, b ); + + BOOST_TEST( r == 3 ); + } + + { + int const a = 1; + + int r = boost::bind( fv2_3, _1, _2 )( a, 2 ); + + BOOST_TEST( r == 3 ); + } + + { + int const b = 2; + + int r = boost::bind( fv2_3, _1, _2 )( 1, b ); + + BOOST_TEST( r == 3 ); + } + + { + int r = boost::bind( fv2_3, _1, _2 )( 1, 2 ); + + BOOST_TEST( r == 3 ); + } +} + +int main() +{ + test(); + return boost::report_errors(); +} From 42b5cef177603328ead66bc6a98a3067aebc433d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 20 Mar 2015 18:16:44 +0200 Subject: [PATCH 4/4] Better argument forwarding when rvalue references are available. --- include/boost/bind/bind.hpp | 292 +++++++++++++++++++++++++++++++++++- 1 file changed, 290 insertions(+), 2 deletions(-) diff --git a/include/boost/bind/bind.hpp b/include/boost/bind/bind.hpp index fb67097..924d055 100644 --- a/include/boost/bind/bind.hpp +++ b/include/boost/bind/bind.hpp @@ -859,7 +859,295 @@ public: // bind_t -#ifndef BOOST_NO_VOID_RETURNS +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +template< class A > struct list_add_cref +{ + typedef A const & type; +}; + +template< class A > struct list_add_cref< A& > +{ + typedef A & type; +}; + +template class bind_t +{ +private: + + F f_; + L l_; + +public: + + typedef typename result_traits::type result_type; + typedef bind_t this_type; + + bind_t( F f, L const & l ): f_( f ), l_( l ) {} + + // + + result_type operator()() + { + list0 a; + return l_( type(), f_, a, 0 ); + } + + result_type operator()() const + { + list0 a; + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1 ) + { + list1< typename list_add_cref::type > a( a1 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1 ) const + { + list1< typename list_add_cref::type > a( a1 ); + return l_(type(), f_, a, 0); + } + + template result_type operator()( A1 && a1, A2 && a2 ) + { + list2< typename list_add_cref::type, typename list_add_cref::type > a( a1, a2 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2 ) const + { + list2< typename list_add_cref::type, typename list_add_cref::type > a( a1, a2 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3 ) + { + list3< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3 ) const + { + list3< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4 ) + { + list4< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4 ) const + { + list4< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5 ) + { + list5< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5 ) const + { + list5< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6 ) + { + list6< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6 ) const + { + list6< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7 ) + { + list7< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6, a7 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7 ) const + { + list7< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6, a7 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8 ) + { + list8< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6, a7, a8 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8 ) const + { + list8< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6, a7, a8 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8, A9 && a9 ) + { + list9< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8, A9 && a9 ) const + { + list9< + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type, + typename list_add_cref::type + > a( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + + return l_( type(), f_, a, 0 ); + } + + // + + template result_type eval( A & a ) + { + return l_( type(), f_, a, 0 ); + } + + template result_type eval( A & a ) const + { + return l_( type(), f_, a, 0 ); + } + + template void accept( V & v ) const + { +#if !defined( BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP ) && !defined( __BORLANDC__ ) + using boost::visit_each; +#endif + + BOOST_BIND_VISIT_EACH( v, f_, 0 ); + l_.accept( v ); + } + + bool compare( this_type const & rhs ) const + { + return ref_compare( f_, rhs.f_, 0 ) && l_ == rhs.l_; + } +}; + +#elif !defined( BOOST_NO_VOID_RETURNS ) template class bind_t { @@ -875,7 +1163,7 @@ public: }; -#else +#else // no void returns template struct bind_t_generator {