[local] Help for the Alternatives section

Hello all, I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... . How can I program the following code (its local function and `factor` constant binding) using Boost.Phoenix, Boost.Lambda, and C++0x lambda functions? If you know, can you please reply with the actual code? #include <boost/local/function.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; void BOOST_LOCAL_FUNCTION_PARAMS(double num, // Variable `factor` bound as constant. bind& sum, const bind& factor) { sum += factor * num; std::cout << "Summed: " << sum << std::endl; } BOOST_LOCAL_FUNCTION_NAME(add) std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; // Local function `add` passed as template parameter. std::for_each(v.begin(), v.end(), add); return 0; } Thank you very much! -- Lorenzo

AMDG On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote:
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... .
How can I program the following code (its local function and `factor` constant binding) using Boost.Phoenix, Boost.Lambda, and C++0x lambda functions? If you know, can you please reply with the actual code?
#include <boost/lambda/lambda.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; using namespace boost::lambda; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; // Local function `add` passed as template parameter. std::for_each(v.begin(), v.end(), ( sum += factor * _1, var(std::cout) << "Summed: " << var(sum) << "\n") ); return 0; } In Christ, Steven Watanabe

On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... .
How can I program the following code (its local function and `factor` constant binding) using Boost.Phoenix, Boost.Lambda, and C++0x lambda functions? If you know, can you please reply with the actual code?
Phoenix version: #include <boost/phoenix/phoenix.hpp> #include <boost/phoenix/statement.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; using namespace boost::phoenix; using namespace boost::phoenix::placeholders; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( ref(sum) += factor * _1, std::cout << "Summed: " << ref(sum) << "\n" ) ); return 0; } -- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

AMDG On 03/26/2011 04:27 PM, Michael Caisse wrote:
#include <boost/phoenix/phoenix.hpp> #include <boost/phoenix/statement.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
using namespace boost::phoenix; using namespace boost::phoenix::placeholders;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( ref(sum) += factor * _1, std::cout << "Summed: " << ref(sum) << "\n" ) ); return 0; }
This is incorrect. std::cout << "Summed: " is evaluated eagerly. In Christ, Steven Watanabe

On 03/26/2011 04:46 PM, Steven Watanabe wrote:
AMDG
On 03/26/2011 04:27 PM, Michael Caisse wrote:
#include <boost/phoenix/phoenix.hpp> #include <boost/phoenix/statement.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
using namespace boost::phoenix; using namespace boost::phoenix::placeholders;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( ref(sum) += factor * _1, std::cout << "Summed: " << ref(sum) << "\n" ) ); return 0; }
This is incorrect. std::cout << "Summed: " is evaluated eagerly.
In Christ, Steven Watanabe
Sorry about that: std::cout << val("Summed: ") << ref(sum) << "\n" or one of the other possibilities will do fine. michael -- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

On Sat, Mar 26, 2011 at 8:05 PM, Michael Caisse <boost@objectmodelingdesigns.com> wrote:
On 03/26/2011 04:46 PM, Steven Watanabe wrote:
AMDG
On 03/26/2011 04:27 PM, Michael Caisse wrote:
#include <boost/phoenix/phoenix.hpp> #include <boost/phoenix/statement.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
using namespace boost::phoenix; using namespace boost::phoenix::placeholders;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( ref(sum) += factor * _1, std::cout << "Summed: " << ref(sum) << "\n" ) ); return 0; }
This is incorrect. std::cout << "Summed: " is evaluated eagerly.
In Christ, Steven Watanabe
Sorry about that:
std::cout << val("Summed: ") << ref(sum) << "\n"
or one of the other possibilities will do fine.
I tried this but it didn't work... why? #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( boost::phoenix::ref(sum) += factor * boost::spirit::qi::_1, std::cout << boost::phoenix::val("Summed: ") << boost::phoenix::ref(sum) << "\n" )); std::cout << sum << std::endl; return 0; } It prints: Summed: 0 Summed: 0 Summed: 0 0 Instead of: Summed: 10 Summed: 30 Summed: 60 60 -- Lorenzo

On Sunday, March 27, 2011 03:48:11 PM Lorenzo Caminiti wrote:
On Sat, Mar 26, 2011 at 8:05 PM, Michael Caisse <boost@objectmodelingdesigns.com> wrote:
On 03/26/2011 04:46 PM, Steven Watanabe wrote:
AMDG
On 03/26/2011 04:27 PM, Michael Caisse wrote:
#include <boost/phoenix/phoenix.hpp> #include <boost/phoenix/statement.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
using namespace boost::phoenix; using namespace boost::phoenix::placeholders;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( ref(sum) += factor * _1, std::cout << "Summed: " << ref(sum) << "\n" ) ); return 0; }
This is incorrect. std::cout << "Summed: " is evaluated eagerly.
In Christ, Steven Watanabe
Sorry about that:
std::cout << val("Summed: ") << ref(sum) << "\n"
or one of the other possibilities will do fine.
I tried this but it didn't work... why?
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
std::for_each(v.begin(), v.end(), ( boost::phoenix::ref(sum) += factor * boost::spirit::qi::_1, ~~~~~~~~~~~~~~~~~~~~~ This is not the same as boost::phoenix::arg_names::_1. I wonder why it compiled at all.
std::cout << boost::phoenix::val("Summed: ") << boost::phoenix::ref(sum) << "\n" ));
std::cout << sum << std::endl; return 0; }
Correct version is: #include <boost/phoenix/phoenix.hpp> // For Phoenix V2 uncomment this line, and comment the above: #include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( boost::phoenix::ref(sum) += factor * boost::phoenix::arg_names::_1, std::cout << boost::phoenix::val("Summed: ") << boost::phoenix::ref(sum) << "\n" )); std::cout << sum << std::endl; return 0; }

On Sun, Mar 27, 2011 at 9:38 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
Correct version is:
#include <boost/phoenix/phoenix.hpp> // For Phoenix V2 uncomment this line, and comment the above: #include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
std::for_each(v.begin(), v.end(), ( boost::phoenix::ref(sum) += factor * boost::phoenix::arg_names::_1, std::cout << boost::phoenix::val("Summed: ") << boost::phoenix::ref(sum) << "\n" ));
std::cout << sum << std::endl; return 0;
Yes, this works :) Thanks a lot! On a separate note, is there any way I can prevent the following `factor = 0` from compiling (e.g., making factor a const within the Phoenix function expression)? #include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( factor = 0, // <==== Can I prevent this with a compiler error? boost::phoenix::ref(sum) += factor * boost::phoenix::arg_names::_1, std::cout << boost::phoenix::val("Summed: ") << boost::phoenix::ref(sum) << "\n" )); std::cout << sum << std::endl; return 0; } Thanks, -- Lorenzo

On Sunday, March 27, 2011 05:00:03 PM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 9:38 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
Correct version is:
#include <boost/phoenix/phoenix.hpp> // For Phoenix V2 uncomment this line, and comment the above: #include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
std::for_each(v.begin(), v.end(), ( boost::phoenix::ref(sum) += factor * boost::phoenix::arg_names::_1, std::cout << boost::phoenix::val("Summed: ") << boost::phoenix::ref(sum) << "\n" ));
std::cout << sum << std::endl; return 0;
Yes, this works :) Thanks a lot!
On a separate note, is there any way I can prevent the following `factor = 0` from compiling (e.g., making factor a const within the Phoenix function expression)?
#include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
std::for_each(v.begin(), v.end(), ( factor = 0, // <==== Can I prevent this with a compiler error?
No, because this is just plain old C++. assigning zero to a value ... there is nothing what phoenix can do here. The guy who wrote the code could have said: const int factor = 10; assignment would then be impossible^W not allowed.

On Sun, Mar 27, 2011 at 10:07 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On a separate note, is there any way I can prevent the following `factor = 0` from compiling (e.g., making factor a const within the Phoenix function expression)?
#include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
std::for_each(v.begin(), v.end(), ( factor = 0, // <==== Can I prevent this with a compiler error?
No, because this is just plain old C++. assigning zero to a value ... there is nothing what phoenix can do here.
Ok, I understand. Thanks.
The guy who wrote the code could have said: const int factor = 10; assignment would then be impossible^W not allowed.
Yes, but the use case would be to have factor const *only* within the "function" passed to for_each while keeping it mutable in the enclosing scope. Therefore, programmers have to declare factor not-const within main() and I was wondering if there was a way using Phoenix to add the const only locally within the "function" passed to for_each (this is done by Boost.Loccal using "constant-binding" as in `const bind& factor`). -- Lorenzo

On Sunday, March 27, 2011 05:43:39 PM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 10:07 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On a separate note, is there any way I can prevent the following `factor = 0` from compiling (e.g., making factor a const within the Phoenix function expression)?
#include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
std::for_each(v.begin(), v.end(), ( factor = 0, // <==== Can I prevent this with a compiler error?
No, because this is just plain old C++. assigning zero to a value ... there is nothing what phoenix can do here.
Ok, I understand. Thanks.
The guy who wrote the code could have said: const int factor = 10; assignment would then be impossible^W not allowed.
Yes, but the use case would be to have factor const *only* within the "function" passed to for_each while keeping it mutable in the enclosing scope. Therefore, programmers have to declare factor not-const within main() and I was wondering if there was a way using Phoenix to add the const only locally within the "function" passed to for_each (this is done by Boost.Loccal using "constant-binding" as in `const bind& factor`).
Oh right, you can do that ...: let(_a = ref(factor))[...]; // <-- bind as non-const reference let(_a = cref(factor))[...]; // <-- bind as const reference Error messages are a mess currently ... but can be improved. Consider it as a bug.

On Sun, Mar 27, 2011 at 11:35 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Sunday, March 27, 2011 05:43:39 PM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 10:07 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
The guy who wrote the code could have said: const int factor = 10; assignment would then be impossible^W not allowed.
Yes, but the use case would be to have factor const *only* within the "function" passed to for_each while keeping it mutable in the enclosing scope. Therefore, programmers have to declare factor not-const within main() and I was wondering if there was a way using Phoenix to add the const only locally within the "function" passed to for_each (this is done by Boost.Loccal using "constant-binding" as in `const bind& factor`).
Oh right, you can do that ...:
let(_a = ref(factor))[...]; // <-- bind as non-const reference let(_a = cref(factor))[...]; // <-- bind as const reference
Yes, I think that is what I was looking for. I will add it to the Boost.Phoenix example. BTW, can I do the same with Boost.Lambda? Thanks, -- Lorenzo

lcaminiti wrote:
On Sun, Mar 27, 2011 at 11:35 AM, Thomas Heller <thom.heller@googlemail.com> wrote: > On Sunday, March 27, 2011 05:43:39 PM Lorenzo Caminiti wrote: >> On Sun, Mar 27, 2011 at 10:07 AM, Thomas Heller >> <thom.heller@googlemail.com> wrote: >> > The guy who wrote the code could have said: const int factor = 10; > assignment >> > would then be impossible^W not allowed. >> >> Yes, but the use case would be to have factor const *only* within the >> "function" passed to for_each while keeping it mutable in the >> enclosing scope. Therefore, programmers have to declare factor >> not-const within main() and I was wondering if there was a way using >> Phoenix to add the const only locally within the "function" passed to >> for_each (this is done by Boost.Loccal using "constant-binding" as in >> `const bind& factor`). > > Oh right, you can do that ...: > > let(_a = ref(factor))[...]; // <-- bind as non-const reference > let(_a = cref(factor))[...]; // <-- bind as const reference
Yes, I think that is what I was looking for. I will add it to the Boost.Phoenix example.
This worked :)) Finally Boost.Local's Phoenix example reads: #include <boost/spirit/include/phoenix.hpp> #include #include #include int main() { double sum = 0.0; int factor = 10; std::vector v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; // Passed as template parameter and also defined at expression level. std::for_each(v.begin(), v.end(), boost::phoenix::let( // Bind `factor` by constant (reference). boost::phoenix::local_names::_f = boost::phoenix::cref(factor))[ // Unfortunately, body cannot use C++ statement syntax. // Access `sum` by (non-constant) reference. boost::phoenix::ref(sum) += boost::phoenix::local_names::_f * boost::phoenix::arg_names::_1, std::cout << boost::phoenix::val("Summed: ") << boost::phoenix::ref(sum) << "\n" ]); std::cout << sum << std::endl; return 0; } BTW, this is pretty powerful stuff ;) --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 3/29/2011 12:37 AM, lcaminiti wrote:
This worked :)) Finally Boost.Local's Phoenix example reads:
#include<boost/spirit/include/phoenix.hpp> #include #include #include
int main() { double sum = 0.0; int factor = 10;
std::vector v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
// Passed as template parameter and also defined at expression level. std::for_each(v.begin(), v.end(), boost::phoenix::let( // Bind `factor` by constant (reference). boost::phoenix::local_names::_f = boost::phoenix::cref(factor))[ // Unfortunately, body cannot use C++ statement syntax. // Access `sum` by (non-constant) reference. boost::phoenix::ref(sum) += boost::phoenix::local_names::_f * boost::phoenix::arg_names::_1, std::cout<< boost::phoenix::val("Summed: ")<< boost::phoenix::ref(sum)<< "\n" ]);
std::cout<< sum<< std::endl; return 0; }
BTW, this is pretty powerful stuff ;)
I'd use using declarations to avoid code clutter and make the code more readable. int main() { double sum = 0.0; int factor = 10; std::vector v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; using boost::phoenix::let; using boost::phoenix::local_names::_f; using boost::phoenix::cref; using boost::phoenix::ref; using boost::phoenix::arg_names::_1; using boost::phoenix::val; // Passed as template parameter and also defined at expression level. std::for_each(v.begin(), v.end(), let( // Bind `factor` by constant (reference). _f = cref(factor))[ // Unfortunately, body cannot use C++ statement syntax. // Access `sum` by (non-constant) reference. ref(sum) += _f * _1, std::cout << val("Summed: ") << ref(sum) << "\n" ]); std::cout << sum << std::endl; return 0; } Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com

Joel de Guzman-2 wrote:
On 3/29/2011 12:37 AM, lcaminiti wrote: > > This worked :)) Finally Boost.Local's Phoenix example reads: > > #include<boost/spirit/include/phoenix.hpp> > #include > #include > #include > > int main() { > double sum = 0.0; > int factor = 10; > > std::vector v(3); > v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; > > // Passed as template parameter and also defined at expression level. > std::for_each(v.begin(), v.end(), boost::phoenix::let( > // Bind `factor` by constant (reference). > boost::phoenix::local_names::_f = boost::phoenix::cref(factor))[ > // Unfortunately, body cannot use C++ statement syntax. > // Access `sum` by (non-constant) reference. > boost::phoenix::ref(sum) += boost::phoenix::local_names::_f * > boost::phoenix::arg_names::_1, > std::cout<< boost::phoenix::val("Summed: ")<< > boost::phoenix::ref(sum)<< "\n" > ]); > > std::cout<< sum<< std::endl; > return 0; > } > > BTW, this is pretty powerful stuff ;)
I'd use using declarations to avoid code clutter and make the code more readable.
int main() { double sum = 0.0; int factor = 10;
std::vector v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
using boost::phoenix::let; using boost::phoenix::local_names::_f; using boost::phoenix::cref; using boost::phoenix::ref; using boost::phoenix::arg_names::_1; using boost::phoenix::val;
// Passed as template parameter and also defined at expression level. std::for_each(v.begin(), v.end(), let( // Bind `factor` by constant (reference). _f = cref(factor))[ // Unfortunately, body cannot use C++ statement syntax. // Access `sum` by (non-constant) reference. ref(sum) += _f * _1, std::cout << val("Summed: ") << ref(sum) << "\n" ]);
std::cout << sum << std::endl; return 0; }
Yes and I will do the same for the Boost.Lambda example. Thanks. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 03/27/2011 06:48 AM, Lorenzo Caminiti wrote:
On Sat, Mar 26, 2011 at 8:05 PM, Michael Caisse <boost@objectmodelingdesigns.com> wrote:
On 03/26/2011 04:46 PM, Steven Watanabe wrote:
AMDG
On 03/26/2011 04:27 PM, Michael Caisse wrote:
#include<boost/phoenix/phoenix.hpp> #include<boost/phoenix/statement.hpp> #include<iostream> #include<vector> #include<algorithm>
int main() { double sum = 0.0; int factor = 10;
using namespace boost::phoenix; using namespace boost::phoenix::placeholders;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), ( ref(sum) += factor * _1, std::cout<< "Summed: "<< ref(sum)<< "\n" ) ); return 0; }
std::cout<< val("Summed: ")<< ref(sum)<< "\n"
I tried this but it didn't work... why?
Because you didn't try what was pasted above (o; I think it is great that you are putting together an Alternative section.
#include<boost/spirit/include/qi.hpp> #include<boost/spirit/include/phoenix_core.hpp> #include<boost/spirit/include/phoenix_operator.hpp> #include<iostream> #include<vector> #include<algorithm>
int main() { double sum = 0.0; int factor = 10;
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
std::for_each(v.begin(), v.end(), ( boost::phoenix::ref(sum) += factor * boost::spirit::qi::_1, std::cout<< boost::phoenix::val("Summed: ")<< boost::phoenix::ref(sum)<< "\n" ));
std::cout<< sum<< std::endl; return 0; }
-- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

On Sun, Mar 27, 2011 at 12:19 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... .
How can I program the following code (its local function and `factor` constant binding) using Boost.Phoenix, Boost.Lambda, and C++0x lambda functions? If you know, can you please reply with the actual code?
C++0x lambdas: #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), [&](double num){ sum += factor * num; std::cout << "Summed: " << sum << std::endl; }); return 0; } Yechezkel Mett

On Sat, Mar 26, 2011 at 6:19 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
How can I program the following code (its local function and `factor` constant binding) using Boost.Phoenix, Boost.Lambda, and C++0x lambda
***Thanks for the examples but is there a way to make `factor` const in the closure?*** Local functions can do that by `const bind factor` (const value) or `const bind& factor` (const reference). How about Boost.Lambda, Boost.Phoenix, and C++0x lambda? For example, why C++0x doesn't allow the use of const in the closure? Was this proposed to the standard committee? #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; // NOTE `const&` for factor (but not supported by C++0x). std::for_each(v.begin(), v.end(), [&sum, const &factor](double num) { sum += factor * num; std::cout << "Summed: " << sum << std::endl; }); std::cout << sum << std::endl; return 0; }
functions? If you know, can you please reply with the actual code?
#include <boost/local/function.hpp> #include <iostream> #include <vector> #include <algorithm>
int main() { double sum = 0.0; int factor = 10;
void BOOST_LOCAL_FUNCTION_PARAMS(double num, // Variable `factor` bound as constant. bind& sum, const bind& factor) { sum += factor * num; std::cout << "Summed: " << sum << std::endl; } BOOST_LOCAL_FUNCTION_NAME(add)
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; // Local function `add` passed as template parameter. std::for_each(v.begin(), v.end(), add); return 0; }
Thanks. -- Lorenzo

On Sun, Mar 27, 2011 at 3:59 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Sat, Mar 26, 2011 at 6:19 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
How can I program the following code (its local function and `factor` constant binding) using Boost.Phoenix, Boost.Lambda, and C++0x lambda
***Thanks for the examples but is there a way to make `factor` const in the closure?***
C++0x lambdas: #include <iostream> #include <vector> #include <algorithm> int main() { double sum = 0.0; int factor = 10; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), [&, factor](double num){ sum += factor * num; std::cout << "Summed: " << sum << std::endl; }); return 0; } Since factor is captured by copy it can't be modified (unless the keyword "mutable" appears after the parameter list). Yechezkel Mett

On Saturday, March 26, 2011 11:19:46 PM Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... I would really like to see the first row removed ... All alternatives you describe are using C++ syntax ... I know what you mean. But all the examples use regular C++ syntax. Another thing what i really wonder is: You write that local classes can not be passed as a template parameter. I don't really get the difference between the local class and Boost.Local. What about this: int main() { double sum = 0.0; int factor = 10; struct add_impl { double & sum; int const& factor; add_impl(double sum, int factor) : sum(sum), factor(factor) {} void operator()(double num) const { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } }; boost::function<void(double)> add = add_impl(sum, factor); double nums[3] = {1, 2, 3}; std::for_each(nums, nums + 3, add) return 0; } I would be happy if you sched some light on to why this isn't possible but why its possible with using your macros.

On Sun, Mar 27, 2011 at 10:04 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Saturday, March 26, 2011 11:19:46 PM Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
I would really like to see the first row removed ... All alternatives you describe are using C++ syntax ... I know what you mean. But all the examples use regular C++ syntax.
I don't think think that Boost.Lambda and Boost.Phoenix use the usual C++ syntax to program the "function" body. If you suggest a text different than "Program body using C++ syntax" I am happy to consider changing the title of the row but I think the row itself should remain there. This row indicates if the "function" body is programmed using the C++ syntax that programmers normally use to program C++ function bodies (and not other C++ constructs). This also has an effect on the type of compiler error messages that programmers will receive about their "function" body. For example, with Boost.Local programmers will receive the usual compiler error messages they receive when they miss-program a function body but with Boost.Lambda and Boost.Phoenix they will receive different compiler errors which they might be unfamiliar with.
Another thing what i really wonder is: You write that local classes can not be passed as a template parameter. I don't really get the difference between the local class and Boost.Local. What about this:
int main() { double sum = 0.0; int factor = 10;
struct add_impl { double & sum; int const& factor; add_impl(double sum, int factor) : sum(sum), factor(factor) {}
void operator()(double num) const { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } };
boost::function<void(double)> add = add_impl(sum, factor);
Your example compiles on MSVC but it does not compile on GCC. As far as I understand it, this is not standard ISO C++ because you cannot pass the local class as a template parameter (in this case to boost::function). $ g++ -Wall -Werror -I../../.. 01.cpp 01.cpp: In function ‘int main()’: 01.cpp:22: error: conversion from ‘main()::add_impl’ to non-scalar type ‘boost::function<void ()(double)>’ requested Can your example be made to compile on GCC and standard ISO C++?
double nums[3] = {1, 2, 3}; std::for_each(nums, nums + 3, add);
(A semicolumn was missing at the end of the for_each.)
return 0; }
I would be happy if you sched some light on to why this isn't possible but why its possible with using your macros.
Boost.Local uses this trick to pass local functions as template parameters: http://lists.boost.org/Archives/boost/2010/09/170888.php You can see how this trick is actually implemented by the library macros at: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... Thank you very much for your comments. -- Lorenzo

On Sunday, March 27, 2011 05:38:23 PM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 10:04 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Saturday, March 26, 2011 11:19:46 PM Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
I would really like to see the first row removed ... All alternatives you describe are using C++ syntax ... I know what you mean.
But
all the examples use regular C++ syntax.
I don't think think that Boost.Lambda and Boost.Phoenix use the usual C++ syntax to program the "function" body.
Usual is just a point of view.
If you suggest a text different than "Program body using C++ syntax" I am happy to consider changing the title of the row but I think the row itself should remain there.
This row indicates if the "function" body is programmed using the C++ syntax that programmers normally use to program C++ function bodies (and not other C++ constructs).
Well, still misleading. It doesn't make it invalid or "unusual" C++ syntax. We had this discussion before ... It is valid and legal C++. Both in syntax and semantic. The difference is that you need some extra function calls, pay attention to some oddities etc. with phoenix and lambda. But it stays valid C++ syntax.
This also has an effect on the type of compiler error messages that programmers will receive about their "function" body. For example, with Boost.Local programmers will receive the usual compiler error messages they receive when they miss-program a function body but with Boost.Lambda and Boost.Phoenix they will receive different compiler errors which they might be unfamiliar with.
Another thing what i really wonder is: You write that local classes can not be passed as a template parameter. I don't really get the difference between the local class and Boost.Local. What about this:
int main() { double sum = 0.0; int factor = 10;
struct add_impl { double & sum; int const& factor; add_impl(double sum, int factor) : sum(sum), factor(factor) {}
void operator()(double num) const { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } };
boost::function<void(double)> add = add_impl(sum, factor);
Your example compiles on MSVC but it does not compile on GCC. As far as I understand it, this is not standard ISO C++ because you cannot pass the local class as a template parameter (in this case to boost::function).
$ g++ -Wall -Werror -I../../.. 01.cpp 01.cpp: In function ‘int main()’: 01.cpp:22: error: conversion from ‘main()::add_impl’ to non-scalar type ‘boost::function<void ()(double)>’ requested
Can your example be made to compile on GCC and standard ISO C++?
double nums[3] = {1, 2, 3}; std::for_each(nums, nums + 3, add);
(A semicolumn was missing at the end of the for_each.)
return 0; }
Doesn't seem to work ... anyway, what i wanted to know was how your implementation is different from that, I understand that the code is invalid cause function uses templates in the constructor ...
I would be happy if you sched some light on to why this isn't possible but why its possible with using your macros.
Boost.Local uses this trick to pass local functions as template parameters: http://lists.boost.org/Archives/boost/2010/09/170888.php You can see how this trick is actually implemented by the library macros at: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
... doesn't really tell me anything, too verbose. And scattered with implementations details. A small English prose like text would help here ... probably. So it works because add has some pure virtual base class as static type! Aha ...
Thank you very much for your comments.
-- Lorenzo _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Sun, Mar 27, 2011 at 8:20 AM, Thomas Heller <thom.heller@googlemail.com>wrote:
On Sunday, March 27, 2011 05:38:23 PM Lorenzo Caminiti wrote:
[...]
I don't think think that Boost.Lambda and Boost.Phoenix use the usual C++ syntax to program the "function" body.
Usual is just a point of view.
I don't think it's an unfair point of view; and, at the very least, the first row of the table in [1] is a fair distinction to make between the libraries. Can you suggest an alternative for the first row header of the table? - Jeff [1] http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...

On Sun, Mar 27, 2011 at 11:20 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Sunday, March 27, 2011 05:38:23 PM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 10:04 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Saturday, March 26, 2011 11:19:46 PM Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
I would really like to see the first row removed ... All alternatives you describe are using C++ syntax ... I know what you mean.
But
all the examples use regular C++ syntax.
I don't think think that Boost.Lambda and Boost.Phoenix use the usual C++ syntax to program the "function" body.
Usual is just a point of view.
Yes, "usual" it's just a point of you. I can add a footnote stating just that.
If you suggest a text different than "Program body using C++ syntax" I am happy to consider changing the title of the row but I think the row itself should remain there.
This row indicates if the "function" body is programmed using the C++ syntax that programmers normally use to program C++ function bodies (and not other C++ constructs).
Well, still misleading. It doesn't make it invalid or "unusual" C++ syntax.
We had this discussion before ... It is valid and legal C++. Both in syntax and semantic. The difference is that you need some extra function calls, pay attention to some oddities etc. with phoenix and lambda. But it stays valid C++ syntax.
Yes, of course it's all valid C++ since it compiles. I can also add that to the footnote.
Another thing what i really wonder is: You write that local classes can not be passed as a template parameter. I don't really get the difference between the local class and Boost.Local. What about this: ... http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
... doesn't really tell me anything, too verbose. And scattered with implementations details. A small English prose like text would help here ... probably.
So it works because add has some pure virtual base class as static type! Aha ...
OK, I understand. Yes, I will add a paragraph to the docs explaining the trick. Thanks, -- Lorenzo

On Monday, March 28, 2011 04:51:42 AM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 11:20 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Sunday, March 27, 2011 05:38:23 PM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 10:04 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Saturday, March 26, 2011 11:19:46 PM Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
I would really like to see the first row removed ... All alternatives you describe are using C++ syntax ... I know what you
mean. But
all the examples use regular C++ syntax.
I don't think think that Boost.Lambda and Boost.Phoenix use the usual C++ syntax to program the "function" body.
Usual is just a point of view.
Yes, "usual" it's just a point of you. I can add a footnote stating just that.
If you suggest a text different than "Program body using C++ syntax" I am happy to consider changing the title of the row but I think the row itself should remain there.
This row indicates if the "function" body is programmed using the C++ syntax that programmers normally use to program C++ function bodies (and not other C++ constructs).
Well, still misleading. It doesn't make it invalid or "unusual" C++ syntax.
We had this discussion before ... It is valid and legal C++. Both in syntax and semantic. The difference is that you need some extra function calls, pay attention to some oddities etc. with phoenix and lambda. But it stays valid C++ syntax.
Yes, of course it's all valid C++ since it compiles. I can also add that to the footnote.
Maybe "Program body using regular C++ statements" is better suited.

On Mar 28, 2011, at 1:44 AM, Thomas Heller wrote:
On Monday, March 28, 2011 04:51:42 AM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 11:20 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Sunday, March 27, 2011 05:38:23 PM Lorenzo Caminiti wrote:If you suggest a text different than "Program body using C++ syntax" I am
happy to consider changing the title of the row but I think the row itself should remain there.
This row indicates if the "function" body is programmed using the C++ syntax that programmers normally use to program C++ function bodies (and not other C++ constructs).
Well, still misleading. It doesn't make it invalid or "unusual" C++ syntax.
We had this discussion before ... It is valid and legal C++. Both in syntax and semantic. The difference is that you need some extra function calls, pay attention to some oddities etc. with phoenix and lambda. But it stays valid C++ syntax.
Yes, of course it's all valid C++ since it compiles. I can also add that to the footnote.
Maybe "Program body using regular C++ statements" is better suited.
That's what came to my mind too - it's statement syntax versus expression syntax, right? Phoenix has pseudo-statements but they're still in expression syntax. Fun stuff, Gordon

On Monday, March 28, 2011 08:55:45 AM Gordon Woodhull wrote:
On Mar 28, 2011, at 1:44 AM, Thomas Heller wrote:
On Monday, March 28, 2011 04:51:42 AM Lorenzo Caminiti wrote:
On Sun, Mar 27, 2011 at 11:20 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Sunday, March 27, 2011 05:38:23 PM Lorenzo Caminiti wrote:If you
suggest a text different than "Program body using C++ syntax" I am
happy to consider changing the title of the row but I think the row itself should remain there.
This row indicates if the "function" body is programmed using the C++ syntax that programmers normally use to program C++ function bodies (and not other C++ constructs).
Well, still misleading. It doesn't make it invalid or "unusual" C++ syntax.
We had this discussion before ... It is valid and legal C++. Both in syntax and semantic. The difference is that you need some extra function calls, pay attention to some oddities etc. with phoenix and lambda. But it stays valid C++ syntax.
Yes, of course it's all valid C++ since it compiles. I can also add that to the footnote.
Maybe "Program body using regular C++ statements" is better suited.
That's what came to my mind too - it's statement syntax versus expression syntax, right? Phoenix has pseudo-statements but they're still in expression syntax.
Yes. This is a bit confusing: Everything in Phoenix (or BLL) is a C++ Expression (having a return type etc., can be void). Phoenix has a statement module, which emulates C++ statements. As a C++ Expression they have a return type of void. We compose these expressions using expression templates (woohoo!), which we traverse upon evaluation. Phoenix also has something similar to Boost.Local. Not really local functions but you can adapt (almost) any function object (with everything written with C++ statements) to be phoenix statements. So i might even claim that you can write phoenix functions "using usual C++ syntax". At the very least you could also use functions defined with Boost.Local inside phoenix ...
Fun stuff,
indeed :)
Gordon

On Mar 28, 2011, at 2:08 AM, Thomas Heller wrote:
That's what came to my mind too - it's statement syntax versus expression syntax, right? Phoenix has pseudo-statements but they're still in expression syntax.
Yes. This is a bit confusing: Everything in Phoenix (or BLL) is a C++ Expression (having a return type etc., can be void). Phoenix has a statement module, which emulates C++ statements. As a C++ Expression they have a return type of void. We compose these expressions using expression templates (woohoo!), which we traverse upon evaluation.
Sure, I get that. I was suggesting that the most neutral way to describe that row might be Syntax? Statement / Expression
Phoenix also has something similar to Boost.Local. Not really local functions but you can adapt (almost) any function object (with everything written with C++ statements) to be phoenix statements.
It's great that all these techniques work together so well.
So i might even claim that you can write phoenix functions "using usual C++ syntax".
While that's really cool, I think it's confusing matters to say that, at least in this context. It's a function that's been adapted for use with phoenix, it's not what anyone would think of when talking about the phoenix syntax. Gordon

Thomas Heller-7 wrote:
On Monday, March 28, 2011 04:51:42 AM Lorenzo Caminiti wrote: Maybe "Program body using regular C++ statements" is better suited.
Sure. I have changed the row title to this. Thanks. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
You might include compile time and run time benchmarks, information about error message quality, and polymorphic capabilities. Additionally, you might note that with C++0x local classes can be used with templates.

On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard wrote:
On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
You might include compile time and run time benchmarks, information about error message quality, and polymorphic capabilities. Additionally, you might note that with C++0x local classes can be used with templates.
Just did a quick test ... code is attached ... $ time g++ -O3 -I. -Wall -Wextra add.cpp -o add real 0m0.657s user 0m0.583s sys 0m0.067s $ time ./add 1e+12 real 0m35.641s user 0m35.618s sys 0m0.017s $ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix real 0m3.385s user 0m3.160s sys 0m0.217s thomas@sunshine ~/programming/local $ time ./add_phoenix 1e+12 real 0m6.648s user 0m6.643s sys 0m0.007s

Thomas Heller-7 wrote:
On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard wrote: > On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote: > > Hello all, > > > > I am updating Boost.Local docs and I could use a some help in getting > > the Alternatives section right > > http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... > > You might include compile time and run time benchmarks, information > about error message quality, and polymorphic capabilities. > Additionally, you might note that with C++0x local classes can be used > with templates.
Just did a quick test ... code is attached ...
$ time g++ -O3 -I. -Wall -Wextra add.cpp -o add
real 0m0.657s user 0m0.583s sys 0m0.067s
$ time ./add 1e+12
real 0m35.641s user 0m35.618s sys 0m0.017s
$ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix
real 0m3.385s user 0m3.160s sys 0m0.217s thomas@sunshine ~/programming/local $ time ./add_phoenix 1e+12
real 0m6.648s user 0m6.643s sys 0m0.007s
This is not a fare comparison because add.cpp contains also local blocks and exits while add_boost_phoenix.cpp contains only local functions. The comparison should be made between add_boost_local.cpp and add_boost_phoenix.cpp (see below). The example names got a bit confusing and I will rename add.cpp to add_funciton_block_exit.cpp to avoid similar misunderstandings in the future. A quick compile and run time comparison using Cygwin. I have ran `time` 3 times and I am reporting the result with the middle `real` value. I will get more statistically meaningful results (avg and std-dev over 100 executions...) and on a real Linux system. Compile-Time ($ time g++ -O3 -Wall -Wextra -I... ) ------------- Boost.Local (add_boost_local.cpp) real = 6.188 s user = 0.885 s system = 1.495 s Local Classes (add_local_class.cpp) real = 3.828 s user = 0.525 s system = 0.464 s C++0x Lambas (add_cpp0x_lambda.cpp) Not available. Boost.Lambda (add_boost_lambda.cpp) real = 5.515 s user = 0.948 s system = 1.136 s Boost.Phoenix (add_boost_phoenix.cpp) real = 12.641 s user = 3.619 s system = 3.074 s Run-Time ($ time ) --------- Boost.Local (add_boost_local.cpp) real = 0.547 s user = 0.030 s system = 0.030 s Local Classes (add_local_class.cpp) real = 0.532 s user = 0.030 s system = 0.061 s C++0x Lambas (add_cpp0x_lambda.cpp) Not available. Boost.Lambda (add_boost_lambda.cpp) real = 0.438 s user = 0.030 s system = 0.046s Boost.Phoenix (add_boost_phoenix.cpp) real = 0.500 s user = 0.030 s system = 0.046 s These Boost.Local compile and run time performances look decent to me when compared with the other approaches (including the local class functor). --Lorenzo http://boost.2283326.n4.nabble.com/file/n3412415/add_boost_local.cpp add_boost_local.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_local_class.cpp add_local_class.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_cpp0x_lambda.cpp add_cpp0x_lambda.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_boost_lambda.cpp add_boost_lambda.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_boost_phoenix.cpp add_boost_phoenix.cpp -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Monday, March 28, 2011 07:03:46 PM lcaminiti wrote:
Thomas Heller-7 wrote:
On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard wrote: > On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote: > > Hello all, > > > > I am updating Boost.Local docs and I could use a some help in getting > > the Alternatives section right > >
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
> > You might include compile time and run time benchmarks, information > about error message quality, and polymorphic capabilities. > Additionally, you might note that with C++0x local classes can be used > with templates.
Just did a quick test ... code is attached ...
$ time g++ -O3 -I. -Wall -Wextra add.cpp -o add
real 0m0.657s user 0m0.583s sys 0m0.067s
$ time ./add 1e+12
real 0m35.641s user 0m35.618s sys 0m0.017s
$ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix
real 0m3.385s user 0m3.160s sys 0m0.217s thomas@sunshine ~/programming/local $ time ./add_phoenix 1e+12
real 0m6.648s user 0m6.643s sys 0m0.007s
This is not a fare comparison because add.cpp contains also local blocks and exits while add_boost_phoenix.cpp contains only local functions. The comparison should be made between add_boost_local.cpp and add_boost_phoenix.cpp (see below). The example names got a bit confusing and I will rename add.cpp to add_funciton_block_exit.cpp to avoid similar misunderstandings in the future.
Seriously? Did you even look at the files i attached?
A quick compile and run time comparison using Cygwin. I have ran `time` 3 times and I am reporting the result with the middle `real` value. I will get more statistically meaningful results (avg and std-dev over 100 executions...) and on a real Linux system.
Compile-Time ($ time g++ -O3 -Wall -Wextra -I... ) ------------- Boost.Local (add_boost_local.cpp) real = 6.188 s user = 0.885 s system = 1.495 s Local Classes (add_local_class.cpp) real = 3.828 s user = 0.525 s system = 0.464 s C++0x Lambas (add_cpp0x_lambda.cpp) Not available. Boost.Lambda (add_boost_lambda.cpp) real = 5.515 s user = 0.948 s system = 1.136 s Boost.Phoenix (add_boost_phoenix.cpp) real = 12.641 s user = 3.619 s system = 3.074 s
Run-Time ($ time ) --------- Boost.Local (add_boost_local.cpp) real = 0.547 s user = 0.030 s system = 0.030 s Local Classes (add_local_class.cpp) real = 0.532 s user = 0.030 s system = 0.061 s C++0x Lambas (add_cpp0x_lambda.cpp) Not available. Boost.Lambda (add_boost_lambda.cpp) real = 0.438 s user = 0.030 s system = 0.046s Boost.Phoenix (add_boost_phoenix.cpp) real = 0.500 s user = 0.030 s system = 0.046 s
These Boost.Local compile and run time performances look decent to me when compared with the other approaches (including the local class functor).
--Lorenzo
http://boost.2283326.n4.nabble.com/file/n3412415/add_boost_local.cpp add_boost_local.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_local_class.cpp add_local_class.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_cpp0x_lambda.cpp add_cpp0x_lambda.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_boost_lambda.cpp add_boost_lambda.cpp http://boost.2283326.n4.nabble.com/file/n3412415/add_boost_phoenix.cpp add_boost_phoenix.cpp
Are you serious? Please write real benchmarks. By executing the resulting binaries of your code examples, the runtime is mainly dominated by process setup and the output on stdout. Take a look here: https://svn.boost.org/svn/boost/trunk/libs/spirit/optimization/ Again: Seriously?

Thomas Heller-7 wrote:
On Monday, March 28, 2011 07:03:46 PM lcaminiti wrote: > > Thomas Heller-7 wrote: > > > > On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard wrote: > > > On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote: > > > > Hello all, > > > > > > > > I am updating Boost.Local docs and I could use a some help in > > getting > > > > the Alternatives section right > > > > > > http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... > > > > > > You might include compile time and run time benchmarks, information > > > about error message quality, and polymorphic capabilities. > > > Additionally, you might note that with C++0x local classes can be > > used > > > with templates. > > > > Just did a quick test ... code is attached ... > > > > $ time g++ -O3 -I. -Wall -Wextra add.cpp -o add > > > > real 0m0.657s > > user 0m0.583s > > sys 0m0.067s > > > > $ time ./add > > 1e+12 > > > > real 0m35.641s > > user 0m35.618s > > sys 0m0.017s > > > > $ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix > > > > real 0m3.385s > > user 0m3.160s > > sys 0m0.217s > > thomas@sunshine ~/programming/local $ time ./add_phoenix > > 1e+12 > > > > real 0m6.648s > > user 0m6.643s > > sys 0m0.007s > > > > This is not a fare comparison because add.cpp contains also local blocks and > exits while add_boost_phoenix.cpp contains only local functions. The > comparison should be made between add_boost_local.cpp and > add_boost_phoenix.cpp (see below). The example names got a bit confusing and > I will rename add.cpp to add_funciton_block_exit.cpp to avoid similar > misunderstandings in the future.
Seriously? Did you even look at the files i attached?
Ooops... no, I didn't. I have files with the exact same name in sandbox/local/libs/local/examples so I assumed you attached these files...
Are you serious? Please write real benchmarks. By executing the resulting binaries of your code examples, the runtime is mainly dominated by process setup and the output on stdout.
Take a look here: https://svn.boost.org/svn/boost/trunk/libs/spirit/optimization/
I have looked at the files you have attached now and I see what you mean. Please scratch my previous benchmark numbers. I will run correct tests more along the lines of what you suggested.
Again: Seriously?
Well... yes seriously... but seriously wrong :) --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

Message du 28/03/11 19:52 De : "lcaminiti" A : boost@lists.boost.org Copie à : Objet : Re: [boost] [local] Help for the Alternatives section
Thomas Heller-7 wrote:
On Monday, March 28, 2011 07:03:46 PM lcaminiti wrote:
Thomas Heller-7 wrote:
On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard
wrote:
On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
You might include compile time and run time benchmarks,
information
about error message quality, and polymorphic capabilities. Additionally, you might note that with C++0x local classes can be used with templates.
Just did a quick test ... code is attached ...
$ time g++ -O3 -I. -Wall -Wextra add.cpp -o add
real 0m0.657s user 0m0.583s sys 0m0.067s
$ time ./add 1e+12
real 0m35.641s user 0m35.618s sys 0m0.017s
$ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix
real 0m3.385s user 0m3.160s sys 0m0.217s thomas@sunshine ~/programming/local $ time ./add_phoenix 1e+12
real 0m6.648s user 0m6.643s sys 0m0.007s
This is not a fare comparison because add.cpp contains also local blocks and exits while add_boost_phoenix.cpp contains only local functions. The comparison should be made between add_boost_local.cpp and add_boost_phoenix.cpp (see below). The example names got a bit confusing and I will rename add.cpp to add_funciton_block_exit.cpp to avoid similar misunderstandings in the future.
Seriously? Did you even look at the files i attached?
Ooops... no, I didn't. I have files with the exact same name in sandbox/local/libs/local/examples so I assumed you attached these files...
Are you serious? Please write real benchmarks. By executing the resulting binaries of your code examples, the runtime is mainly dominated by process setup and the output on stdout.
Take a look here: https://svn.boost.org/svn/boost/trunk/libs/spirit/optimization/
I have looked at the files you have attached now and I see what you mean. Please scratch my previous benchmark numbers. I will run correct tests more along the lines of what you suggested.
Hi Lorenzo, To complete the performance comparison I will add a hand written test which should be used as reference implementation. for (size_t i = 0; i < v.size(); ++i) { sum += factor * num; } and a non-local functor so it can be used with foreach (which seems to perform better than the manual for (size_t i = 0; i < v.size(); ++i) struct non_local_add { // Unfortunately, extra code to manually program the functor class. local_add(double& _sum, int _factor): sum(_sum), factor(_factor) {} void operator()(double num) { // Body uses C++ statement syntax. sum += factor * num; std::cout << "Summed: " << sum << std::endl; } private: // Unfortunately, cannot bind so repeat variable types. double& sum; // Access `sum` by (non-constant) reference. const int factor; // Make `factor` constant. } ; int main() { double sum = 0.0; int factor = 10; std::vector v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; non_local_add add(sum, factor); // Non Local functor `add` passed as template parameter. std::for_each(v.begin(), v.end(), add); std::cout << sum << std::endl; return 0; } In addition you can use Boost.Chrono so you measure exactly what you want to measure,i.e. the add instantiation + the foreach without setup and output. Best, Vicente P.S. I see that others have the same issue I have when posting in this list with the '<' and '>' symbols. From where you sent your last messages that results in html codes?

Vicente Botet wrote:
> Message du 28/03/11 19:52 > De : "lcaminiti" > A : boost@lists.boost.org > Copie à : > Objet : Re: [boost] [local] Help for the Alternatives section > > > Thomas Heller-7 wrote: > > > > On Monday, March 28, 2011 07:03:46 PM lcaminiti wrote: > > > > > > Thomas Heller-7 wrote: > > > > > > > > On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard > > wrote: > > > > > On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote: > > > > > > Hello all, > > > > > > > > > > > > I am updating Boost.Local docs and I could use > > a some help in > > > > getting > > > > > > the Alternatives section right > > > > > > > > > > > > http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... > > > > > > > > > > You might include compile time and run time benchmarks, > > information > > > > > about error message quality, and polymorphic > > capabilities. > > > > > Additionally, you might note that with C++0x local > > classes can be > > > > used > > > > > with templates. > > > > > > > > Just did a quick test ... code is attached ... > > > > > > > > $ time g++ -O3 -I. -Wall -Wextra add.cpp -o add > > > > > > > > real 0m0.657s > > > > user 0m0.583s > > > > sys 0m0.067s > > > > > > > > $ time ./add > > > > 1e+12 > > > > > > > > real 0m35.641s > > > > user 0m35.618s > > > > sys 0m0.017s > > > > > > > > $ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o > > add_phoenix > > > > > > > > real 0m3.385s > > > > user 0m3.160s > > > > sys 0m0.217s > > > > thomas@sunshine ~/programming/local $ time ./add_phoenix > > > > 1e+12 > > > > > > > > real 0m6.648s > > > > user 0m6.643s > > > > sys 0m0.007s > > > > > > > > > > This is not a fare comparison because add.cpp contains also local > > blocks and > > > exits while add_boost_phoenix.cpp contains only local functions. The > > > comparison should be made between add_boost_local.cpp and > > > add_boost_phoenix.cpp (see below). The example names got a bit > > confusing and > > > I will rename add.cpp to add_funciton_block_exit.cpp to avoid similar > > > misunderstandings in the future. > > > > Seriously? Did you even look at the files i attached? > > > > Ooops... no, I didn't. I have files with the exact same name in > sandbox/local/libs/local/examples so I assumed you attached these files... > > > > > Are you serious? Please write real benchmarks. By executing the resulting > > binaries of your code examples, the runtime is mainly dominated by process > > setup > > and the output on stdout. > > > > Take a look here: > > https://svn.boost.org/svn/boost/trunk/libs/spirit/optimization/ > > > > I have looked at the files you have attached now and I see what you mean. > Please scratch my previous benchmark numbers. I will run correct tests more > along the lines of what you suggested.
Hi Lorenzo,
To complete the performance comparison I will add a hand written test which should be used as reference implementation.
for (size_t i = 0; i < v.size(); ++i) { sum += factor * num; }
and a non-local functor so it can be used with foreach (which seems to perform better than the manual for (size_t i = 0; i < v.size(); ++i)
struct non_local_add { // Unfortunately, extra code to manually program the functor class. local_add(double& _sum, int _factor): sum(_sum), factor(_factor) {}
void operator()(double num) { // Body uses C++ statement syntax. sum += factor * num; std::cout << "Summed: " << sum << std::endl; }
private: // Unfortunately, cannot bind so repeat variable types. double& sum; // Access `sum` by (non-constant) reference. const int factor; // Make `factor` constant. } ;
int main() { double sum = 0.0; int factor = 10;
std::vector v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0;
non_local_add add(sum, factor);
// Non Local functor `add` passed as template parameter. std::for_each(v.begin(), v.end(), add);
std::cout << sum << std::endl; return 0; }
Yes, I am already looking as the non-local functor and the local functor without for_each as baselines.
In addition you can use Boost.Chrono so you measure exactly what you want to measure,i.e. the add instantiation + the foreach without setup and output.
I will look into Boost.Chrono. If you had time to sketch a bit of code on how I'd use Chrono in this case, it'd get me started. Thanks. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

lcaminiti wrote:
benchmark numbers. I will run correct tests more along the lines of what you suggested.
Hello all, I am looking into why Boost.Local has a long run-time and I run into something strange that I cannot explain... I am still looking into this but I wanted to ask if anyone has some insight. Consider the following code which uses Boost.ScopeExit type deduction and a local functor class (these are bits that Boost.Local uses internally): #include <boost/local/function.hpp> #include #include #include int main() { double sum = 0.0; int factor = 10; typedef void (*tag)(int factor); typedef BOOST_TYPEOF(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(factor, (tag)0))) wrapped_t; typedef wrapped_t::type capture_t; struct params_t { typedef capture_t param_t; boost::scope_exit::aux::member<param_t, tag> param; } params = { { boost::scope_exit::aux::deref(factor, (tag)0) } }; // ******* std::cout << params.param.value << std::endl; // (1) std::vector v(1000000); // (2) // ******* class local_add { public: explicit local_add(double& _sum, int _factor): sum_(_sum), factor_(_factor) { } void operator()(double num) { return body(factor_, sum_, num); } private: double& sum_; int factor_; void body(const int factor, double& sum, double num) const { sum += factor * num; } } add(sum, factor); std::fill(v.begin(), v.end(), 10); for (size_t i = 0; i < 10000; ++i) { for (size_t j = 0; j < v.size(); ++j) { add(v[j]); } } std::cout << sum << std::endl; return 0; } This compiles and runs as: $ time g++ -O3 -Wall -Wextra -I../../.. l09.cpp -ol09 real 0m5.969s user 0m0.994s sys 0m1.435s $ time ./l09 10 1e+12 real 0m16.297s user 0m15.827s sys 0m0.109s But if I simply swap lines (1) and (2): $ diff -u l09.cpp l08.cpp --- l09.cpp 2011-03-29 12:21:16.034974600 -0400 +++ l08.cpp 2011-03-29 12:21:08.160478600 -0400 @@ -20,8 +20,8 @@ }; - std::cout << params.param.value << std::endl; std::vector v(1000000); + std::cout << params.param.value << std::endl; class local_add { Then it runs _much_ slower: $ time g++ -O3 -Wall -Wextra -I../../.. l08.cpp -ol08 real 0m5.875s user 0m0.821s sys 0m1.231s $ time ./l08 10 1e+12 real 0m44.469s user 0m43.874s sys 0m0.015s Why swapping lines (1) and (2) changes the run-time? I don't understand it at all... I must be missing something... Thank you in advance. -- Lorenzo http://boost.2283326.n4.nabble.com/file/n3415414/l08.exe l08.exe http://boost.2283326.n4.nabble.com/file/n3415414/l09.exe l09.exe -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

lcaminiti wrote:
lcaminiti wrote:
benchmark numbers. I will run correct tests more along the lines of what you suggested.
Hello all,
I am looking into why Boost.Local has a long run-time and I run into something strange that I cannot explain... I am still looking into this but I wanted to ask if anyone has some insight.
Consider the following code which uses Boost.ScopeExit type deduction and a local functor class (these are bits that Boost.Local uses internally):
#include <boost/local/function.hpp> #include #include #include
int main() { double sum = 0.0; int factor = 10;
typedef void (*tag)(int factor); typedef BOOST_TYPEOF(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(factor, (tag)0))) wrapped_t; typedef wrapped_t::type capture_t; struct params_t { typedef capture_t param_t; boost::scope_exit::aux::member<param_t, tag> param; } params = { { boost::scope_exit::aux::deref(factor, (tag)0) } };
// ******* std::cout << params.param.value << std::endl; // (1) std::vector v(1000000); // (2) // *******
class local_add { public: explicit local_add(double& _sum, int _factor): sum_(_sum), factor_(_factor) { } void operator()(double num) { return body(factor_, sum_, num); } private: double& sum_; int factor_;
void body(const int factor, double& sum, double num) const { sum += factor * num; } } add(sum, factor);
std::fill(v.begin(), v.end(), 10); for (size_t i = 0; i < 10000; ++i) { for (size_t j = 0; j < v.size(); ++j) { add(v[j]); } }
std::cout << sum << std::endl; return 0; }
This compiles and runs as:
$ time g++ -O3 -Wall -Wextra -I../../.. l09.cpp -ol09
real 0m5.969s user 0m0.994s sys 0m1.435s
$ time ./l09 10 1e+12
real 0m16.297s user 0m15.827s sys 0m0.109s
But if I simply swap lines (1) and (2):
$ diff -u l09.cpp l08.cpp --- l09.cpp 2011-03-29 12:21:16.034974600 -0400 +++ l08.cpp 2011-03-29 12:21:08.160478600 -0400 @@ -20,8 +20,8 @@ };
- std::cout << params.param.value << std::endl; std::vector v(1000000); + std::cout << params.param.value << std::endl;
class local_add {
Then it runs _much_ slower:
$ time g++ -O3 -Wall -Wextra -I../../.. l08.cpp -ol08
real 0m5.875s user 0m0.821s sys 0m1.231s
$ time ./l08 10 1e+12
real 0m44.469s user 0m43.874s sys 0m0.015s
Why swapping lines (1) and (2) changes the run-time? I don't understand it at all... I must be missing something...
Thank you in advance.
-- Lorenzo
http://boost.2283326.n4.nabble.com/file/n3415414/l08.exe?by-user=t l08.exe http://boost.2283326.n4.nabble.com/file/n3415414/l09.exe?by-user=t l09.exe
I attached the wrongs files. Here's the source: http://boost.2283326.n4.nabble.com/file/n3415420/l09.cpp l09.cpp http://boost.2283326.n4.nabble.com/file/n3415420/l08.cpp l08.cpp -- Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Mon, Mar 28, 2011 at 12:21 PM, Thomas Heller <thom.heller@googlemail.com> wrote:
Are you serious? Please write real benchmarks. By executing the resulting
Hello all, I have profiled Boost.Local against all the alternative methods I know for local functions: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... I was able to optimize Boost.Local code so it always runs as fast as Local Functors. However, both Boost.Local and Local Functors run significantly slower than Global Functors, Boost.Lambda, and Boost.Phoenix on non C++03 compilers (see "Boost.Local Compliant"). On C++03 compilers, Boost.Local runs faster than Local Functors and as fast as Global Functors, Boost.Lambda, and Boost.Phoenix. All of that when compiler optimization is used; When no compiler optimization is used Boost.Local runs faster than both Boost.Lambda and Boost.Phoenix. Boost.Local always compiles relatively fast and the same is true for Boost.Lambda but not for Boost.Phoenix. I have also listed binary sizes. For the run-time, the point seems to be that the Boost.Local trick that allows to pass local classes as template parameters requires 1 indirect function call via a function pointer: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... This indirect function pointer call can only be resolved at run-time so compiler optimizations that inline all Boost.Lambda and Boost.Phoenix functor calls cannot inline Boost.Local functor calls. On C++03 compilers, Boost.Local passes the local class functor directly as template parameter avoiding the function pointer indirect call and therefore allowing for inlining all the Boost.Local functor calls when compiler optimization is enabled. I would think that the run-time cost of Boost.Local on non C++03 compilers (i.e., the use of 1 function pointer in resolving the local function call) might still be acceptable in applications that already use a number of indirect function calls (via function pointers, virtual functions, etc). Furthermore, I have not experimented how the run-time performances of Boost.Local and the other approaches are affected by programming more complex instructions in the local function body (the local function used in this analysis simply adds the elements of an array and it contains only one instruction `sum += factor * num`). What do you think? Thanks. -- Lorenzo

On 24/04/11 03:56, Lorenzo Caminiti wrote:
On Mon, Mar 28, 2011 at 12:21 PM, Thomas Heller <thom.heller@googlemail.com> wrote:
Are you serious? Please write real benchmarks. By executing the resulting
Hello all,
I have profiled Boost.Local against all the alternative methods I know for local functions: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
I feel that including the "for loop" implementations is cluttering the graphs to no useful purpose. The only place it's obviously different from the other is in the unoptimized runtime. Also, I'd suggest putting the pictures in a different order: runtime first, then compile time, then binary size; I guess that's closer to what a typical developer cares about. It might also help to put the legend at the top; I didn't notice it for a while and I was confused by how the entries in the graphs corresponded to the source files linked to.
I was able to optimize Boost.Local code so it always runs as fast as Local Functors. However, both Boost.Local and Local Functors run significantly slower than Global Functors, Boost.Lambda, and Boost.Phoenix on non C++03 compilers (see "Boost.Local Compliant"). On C++03 compilers, Boost.Local runs faster than Local Functors and as fast as Global Functors, Boost.Lambda, and Boost.Phoenix.
When you say "non C++03" and "C++03", do you in fact mean "non C++0x" and "C++0x"? (Indeed, you may wish to dare to call it "C++11" at this point). These results and comments don't make much sense otherwise.
For the run-time, the point seems to be that the Boost.Local trick that allows to pass local classes as template parameters requires 1 indirect function call via a function pointer: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... This indirect function pointer call can only be resolved at run-time so compiler optimizations that inline all Boost.Lambda and Boost.Phoenix functor calls cannot inline Boost.Local functor calls.
This is not really true. The call *could* be resolved at compile-time in theory, it's just that no compiler has been observed to do it. John

On Sun, Apr 24, 2011 at 6:09 AM, John Bytheway <jbytheway+boost@gmail.com> wrote:
On 24/04/11 03:56, Lorenzo Caminiti wrote:
On Mon, Mar 28, 2011 at 12:21 PM, Thomas Heller <thom.heller@googlemail.com> wrote:
Are you serious? Please write real benchmarks. By executing the resulting
Hello all,
I have profiled Boost.Local against all the alternative methods I know for local functions:
I have made some changes to profiling for MSVC 8.0 on Windows XP plus I have added profiling for GCC 4.5.1 with C++0x (including lambdas) on Linux and GCC 4.3.4 (plain ISO C++) on Cygwin: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
I feel that including the "for loop" implementations is cluttering the graphs to no useful purpose. The only place it's obviously different from the other is in the unoptimized runtime. Also, I'd suggest putting the pictures in a different order: runtime first, then compile time, then binary size; I guess that's closer to what a typical developer cares about. It might also help to put the legend at the top; I didn't notice it for a while and I was confused by how the entries in the graphs corresponded to the source files linked to.
I have remove the Boost.Local for-loop implementation but I have left the for-loop implementations only for Local Function Inline (before called NAME_OPTIMIZED) and for Local Functor because they cannot be passed as template parameters on ISO C++.
I was able to optimize Boost.Local code so it always runs as fast as Local Functors. However, both Boost.Local and Local Functors run significantly slower than Global Functors, Boost.Lambda, and Boost.Phoenix on non C++03 compilers (see "Boost.Local Compliant"). On C++03 compilers, Boost.Local runs faster than Local Functors and as fast as Global Functors, Boost.Lambda, and Boost.Phoenix.
When you say "non C++03" and "C++03", do you in fact mean "non C++0x" and "C++0x"? (Indeed, you may wish to dare to call it "C++11" at this point). These results and comments don't make much sense otherwise.
Yes, I have changed that. Specifically I am referring to C++0x N2657 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm .
For the run-time, the point seems to be that the Boost.Local trick that allows to pass local classes as template parameters requires 1 indirect function call via a function pointer: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... This indirect function pointer call can only be resolved at run-time so compiler optimizations that inline all Boost.Lambda and Boost.Phoenix functor calls cannot inline Boost.Local functor calls.
This is not really true. The call *could* be resolved at compile-time in theory, it's just that no compiler has been observed to do it.
Yes, I have tried to state this correctly in Boost.Local docs. -- Lorenzo

lcaminiti wrote:
Thomas Heller-7 wrote:
Just did a quick test ... code is attached ...
$ time g++ -O3 -I. -Wall -Wextra add.cpp -o add
real 0m0.657s user 0m0.583s sys 0m0.067s
$ time ./add 1e+12
real 0m35.641s user 0m35.618s sys 0m0.017s
$ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix
real 0m3.385s user 0m3.160s sys 0m0.217s thomas@sunshine ~/programming/local $ time ./add_phoenix 1e+12
real 0m6.648s user 0m6.643s sys 0m0.007s
This is not a fare comparison because add.cpp contains also local blocks and exits while add_boost_phoenix.cpp contains only local functions. The comparison should be made between add_boost_local.cpp and add_boost_phoenix.cpp (see below). The example names got a bit confusing and I will rename add.cpp to add_funciton_block_exit.cpp to avoid similar misunderstandings in the future.
Sorry, I didn't get the impression that there was some misunderstanding, or that the comparison was unfair. I took from that comparison that Boost.Phoenix takes 6 times longer to compile, but runs 6 times faster than Boost.Local.
A quick compile and run time comparison using Cygwin. I have ran `time` [snip] Run-Time ($ time ) --------- Boost.Local (add_boost_local.cpp) real = 0.547 s user = 0.030 s system = 0.030 s Local Classes (add_local_class.cpp) real = 0.532 s user = 0.030 s system = 0.061 s C++0x Lambas (add_cpp0x_lambda.cpp) Not available. Boost.Lambda (add_boost_lambda.cpp) real = 0.438 s user = 0.030 s system = 0.046s Boost.Phoenix (add_boost_phoenix.cpp) real = 0.500 s user = 0.030 s system = 0.046 s
These Boost.Local compile and run time performances look decent to me when compared with the other approaches (including the local class functor).
Boost.Local has the worst run time of all listed approaches. Why do you think that the performance is decent? For these attached tests, the local function seems to be called only three times. For the test from Thomas Heller, 1000000 * 10000 = 10^10 times. Thomas Heller wrote:
Are you serious? Please write real benchmarks.
Indeed, something seems very strange here. Regards, Thomas

On Mon, Mar 28, 2011 at 2:50 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard wrote:
On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
You might include compile time and run time benchmarks, information about error message quality, and polymorphic capabilities. Additionally, you might note that with C++0x local classes can be used with templates.
Just did a quick test ... code is attached ...
$ time g++ -O3 -I. -Wall -Wextra add.cpp -o add
real 0m0.657s user 0m0.583s sys 0m0.067s
$ time ./add 1e+12
real 0m35.641s user 0m35.618s sys 0m0.017s
$ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix
real 0m3.385s user 0m3.160s sys 0m0.217s thomas@sunshine ~/programming/local $ time ./add_phoenix 1e+12
real 0m6.648s user 0m6.643s sys 0m0.007s
I have done an (hopefully more correct) benchmark of Boost.Local performances compared with the alternative methods -- please check my doing :) In summary: 1) Boost.Phoenix, global functors, and local functors run in ~15s. 2) Boost.Lambda runs in ~40s. 3) Boost.Local runs in ~53s. 4) I don't have a C++0x lambda compiler so I could not benchmark C++0x lambdas. I don't know why Boost.Lambda takes longer than 1). Boost.Local seems to take longer than 1) because of the extra virtual function call introduced by the trick that allows to pass the local struct as a template parameter -- I will follow up with another email to explain this point in detail. ANALYSIS The basic code looks like this (see attachments): #define N 10000 int main() { double sum = 0.0; int factor = 10; void BOOST_LOCAL_FUNCTION_PARAMS( (const double& num) (bind& sum) (const bind& factor) ) { sum += factor * num; } BOOST_LOCAL_FUNCTION_NAME(add) std::vector<double> v(N * 100); std::fill(v.begin(), v.end(), 10); for (size_t n = 0; n < N; ++n) { std::for_each(v.begin(), v.end(), add); } std::cout << sum << std::endl; return 0; } BOOST LOCAL $ time g++ -O3 -I../../.. -Wall -Wextra benchmark_boost_local.cpp real 0m8.330s user 0m1.166s sys 0m1.463s $ time ./a 1e+12 real 0m52.735s user 0m52.109s sys 0m0.077s GLOBAL FUNCTOR $ time g++ -O3 -I../../.. -Wall -Wextra benchmark_global_functor.cpp real 0m5.302s user 0m0.573s sys 0m0.560s $ time ./a 1e+12 real 0m15.167s user 0m14.499s sys 0m0.030s LOCAL FUNCTOR (manual for-loop instead of for_each) $ time g++ -O3 -I../../.. -Wall -Wextra benchmark_local_functor.cpp real 0m5.476s user 0m0.510s sys 0m0.730s $ time ./a 1e+12 real 0m15.392s user 0m14.686s sys 0m0.108s BOOST LAMBDA $ time g++ -O3 -I../../.. -Wall -Wextra benchmark_boost_lambda.cpp real 0m6.631s user 0m0.792s sys 0m1.199s $ time ./a 1e+12 real 0m39.855s user 0m38.905s sys 0m0.061s BOOST PHOENIX $ time g++ -O3 -I../../.. -Wall -Wextra benchmark_boost_phoenix.cpp real 0m14.004s user 0m3.761s sys 0m3.543s $ time ./a 1e+12 real 0m15.727s user 0m14.921s sys 0m0.030s -- Lorenzo

On Sun, Apr 3, 2011 at 1:23 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Mon, Mar 28, 2011 at 2:50 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Monday, March 28, 2011 05:25:13 AM Jeremy Maitin-Shepard wrote:
On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
You might include compile time and run time benchmarks, information about error message quality, and polymorphic capabilities. Additionally, you might note that with C++0x local classes can be used with templates.
Just did a quick test ... code is attached ...
$ time g++ -O3 -I. -Wall -Wextra add.cpp -o add
real 0m0.657s user 0m0.583s sys 0m0.067s
$ time ./add 1e+12
real 0m35.641s user 0m35.618s sys 0m0.017s
$ time g++ -O3 -I. -Wall -Wextra add_boost_phoenix.cpp -o add_phoenix
real 0m3.385s user 0m3.160s sys 0m0.217s thomas@sunshine ~/programming/local $ time ./add_phoenix 1e+12
real 0m6.648s user 0m6.643s sys 0m0.007s
I have done an (hopefully more correct) benchmark of Boost.Local performances compared with the alternative methods -- please check my doing :)
In summary: 1) Boost.Phoenix, global functors, and local functors run in ~15s. 2) Boost.Lambda runs in ~40s. 3) Boost.Local runs in ~53s. 4) I don't have a C++0x lambda compiler so I could not benchmark C++0x lambdas.
I don't know why Boost.Lambda takes longer than 1). Boost.Local seems to take longer than 1) because of the extra virtual function call introduced by the trick that allows to pass the local struct as a template parameter -- I will follow up with another email to explain this point in detail.
ANALYSIS
The basic code looks like this (see attachments):
#define N 10000
int main() { double sum = 0.0; int factor = 10;
void BOOST_LOCAL_FUNCTION_PARAMS( (const double& num) (bind& sum) (const bind& factor) ) { sum += factor * num; } BOOST_LOCAL_FUNCTION_NAME(add)
std::vector<double> v(N * 100); std::fill(v.begin(), v.end(), 10); for (size_t n = 0; n < N; ++n) { std::for_each(v.begin(), v.end(), add); }
std::cout << sum << std::endl; return 0; }
BOOST LOCAL
$ time g++ -O3 -I../../.. -Wall -Wextra benchmark_boost_local.cpp
real 0m8.330s user 0m1.166s sys 0m1.463s
$ time ./a 1e+12
real 0m52.735s user 0m52.109s sys 0m0.077s
GLOBAL FUNCTOR
$ time g++ -O3 -I../../.. -Wall -Wextra benchmark_global_functor.cpp
real 0m5.302s user 0m0.573s sys 0m0.560s
$ time ./a 1e+12
real 0m15.167s user 0m14.499s sys 0m0.030s
LOCAL FUNCTOR (manual for-loop instead of for_each)
$ time g++ -O3 -I../../.. -Wall -Wextra benchmark_local_functor.cpp
real 0m5.476s user 0m0.510s sys 0m0.730s
$ time ./a 1e+12
real 0m15.392s user 0m14.686s sys 0m0.108s
BOOST LAMBDA
$ time g++ -O3 -I../../.. -Wall -Wextra benchmark_boost_lambda.cpp
real 0m6.631s user 0m0.792s sys 0m1.199s
$ time ./a 1e+12
real 0m39.855s user 0m38.905s sys 0m0.061s
BOOST PHOENIX
$ time g++ -O3 -I../../.. -Wall -Wextra benchmark_boost_phoenix.cpp
real 0m14.004s user 0m3.761s sys 0m3.543s
$ time ./a 1e+12
real 0m15.727s user 0m14.921s sys 0m0.030s
The source files are attached. -- Lorenzo

On Sun, Apr 3, 2011 at 1:23 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
I have done an (hopefully more correct) benchmark of Boost.Local performances compared with the alternative methods -- please check my doing :)
In summary: 1) Boost.Phoenix, global functors, and local functors run in ~15s. 2) Boost.Lambda runs in ~40s. 3) Boost.Local runs in ~53s. 4) I don't have a C++0x lambda compiler so I could not benchmark C++0x lambdas.
I don't know why Boost.Lambda takes longer than 1). Boost.Local seems to take longer than 1) because of the extra virtual function call introduced by the trick that allows to pass the local struct as a template parameter -- I will follow up with another email to explain this point in detail.
This is the trick used by Boost.Local to call a function defined within a local struct from a functor passed as template parameter: 1) The local struct inherits from abstract_function and implementing operator(). 2) The local function is of a non-local type `function` so it can be passed as template parameter. 3) The functor `function` calls abstract_function's virtual operator() which in turn calls the local struct implementation of operator(). The following code shows the idea: #include <iostream> #include <vector> #include <algorithm> #define N 10000 template<typename R, typename A0> struct abstract_function { virtual R operator()(A0) = 0; }; template<typename R, typename A0> struct function { function(abstract_function<R, A0>& ref): ptr_(&ref) {} R operator()(A0 a0) { return (*ptr_)(a0); } private: abstract_function<R, A0>* ptr_; }; int main() { double sum = 0.0; int factor = 10; struct add_function: abstract_function<void, const double&> { add_function(double& _sum, const int& _factor): sum_(_sum), factor_(_factor) {} void operator()(const double& num) { return body(num, sum_, factor_); } private: double& sum_; const int& factor_; void body(const double& num, double& sum, const int& factor) { sum += factor * num; } }; add_function functor_add(sum, factor); function<void, const double&> add(functor_add); std::vector<double> v(N * 100); std::fill(v.begin(), v.end(), 10); for (size_t n = 0; n < N; ++n) { // for (size_t i = 0; i < v.size(); ++i) { // functor_add(v[i]); // (1) // add(v[i]); // (2) // } std::for_each(v.begin(), v.end(), add); // (3) OK add as tparam! } std::cout << sum << std::endl; return 0; } The call at line (3) calls functionr::operator() --<<virtual>>--> abstract_function::operator() --> add_function::operator() so the local struct operator() is called. A) Now if I comment line (3), uncomment the for-loop and line (2): ... for (size_t n = 0; n < N; ++n) { for (size_t i = 0; i < v.size(); ++i) { // functor_add(v[i]); // (1) add(v[i]); // (2) } // std::for_each(v.begin(), v.end(), add); // (3) OK add as tparam! } ... This runs in 49s. B) But if I use line (1) instead of (2): ... for (size_t n = 0; n < N; ++n) { for (size_t i = 0; i < v.size(); ++i) { functor_add(v[i]); // (1) // add(v[i]); // (2) } // std::for_each(v.begin(), v.end(), add); // (3) OK add as tparam! } ... This runs in 15s!! As far I can see, line (1) is faster because it does not have the overhead of the virtual function call that line (2) has: A) Line (2) call: functionr::operator() --<<virtual>>--> abstract_function::operator() --> add_function::operator() (runs in 49s) B) Line (1) call: add_function::operator() (runs in 15s) What do you think? Is there any way I can make the A) faster (i.e., run-time similarly to B))? Thank you very much. -- Lorenzo

Message du 03/04/11 19:49 De : "Lorenzo Caminiti" A : boost@lists.boost.org Copie à : Objet : Re: [boost] [local] Help for the Alternatives section
On Sun, Apr 3, 2011 at 1:23 PM, Lorenzo Caminiti wrote:
I have done an (hopefully more correct) benchmark of Boost.Local performances compared with the alternative methods -- please check my doing :)
In summary: 1) Boost.Phoenix, global functors, and local functors run in ~15s. 2) Boost.Lambda runs in ~40s. 3) Boost.Local runs in ~53s. 4) I don't have a C++0x lambda compiler so I could not benchmark C++0x lambdas.
With these timings it seems to me that you will be forced to provide two macro families: one that doesn't use the trick and can be used as template parameter only on compilers supporting this C++0x feature and the other which uses the trick is slow but can be used in a portable way as a template parameter. I guess that this benchmark shows a hard limitation of Boost.Local at least until most of the compilers will accept local structures as template parameters. Best, Vicente

Mathias Gaunard-2 wrote:
On 03/04/2011 21:44, Vicente BOTET wrote:
I guess that this benchmark shows a hard limitation of Boost.Local at least until most of the compilers will accept local structures as template parameters.
Don't all of them do it already, at least in C++0x mode?
I think so (that's the case at least in my experience). Here is the accepted C++0x proposal that allows to pass local (and unnamed) types as template parameters: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

Jeremy Maitin-Shepard-2 wrote:
On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote: > Hello all, > > I am updating Boost.Local docs and I could use a some help in getting > the Alternatives section right > http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
You might include compile time and run time benchmarks, information about error message quality, and polymorphic capabilities. Additionally, you might note that with C++0x local classes can be used with templates.
Good suggestions. I will include all of those. How would the polymorphic (type) row read? (I don't fully understand this...) For example: Type Polymorphism ------------------ Boost.Local: Yes but only of type of bound parameters (not for normal function parameters). Local Classes: No. C++0X Lambdas: Yes but only of type of bound parameters (not for normal function parameters). Boost.Lambda: No?? Boost.Phoenix: No?? Is this correct? Thank you very much. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

AMDG On 03/28/2011 09:41 AM, lcaminiti wrote:
Jeremy Maitin-Shepard-2 wrote:
On 03/26/2011 03:19 PM, Lorenzo Caminiti wrote: > Hello all, > > I am updating Boost.Local docs and I could use a some help in getting > the Alternatives section right > http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
You might include compile time and run time benchmarks, information about error message quality, and polymorphic capabilities. Additionally, you might note that with C++0x local classes can be used with templates.
Good suggestions. I will include all of those.
How would the polymorphic (type) row read? (I don't fully understand this...) For example:
Type Polymorphism ------------------ Boost.Local: Yes but only of type of bound parameters (not for normal function parameters). Local Classes: No. C++0X Lambdas: Yes but only of type of bound parameters (not for normal function parameters). Boost.Lambda: No?? Boost.Phoenix: No??
Is this correct?
I have don't know whether it's correct, because, I have no idea what you are talking about. Boost.Lambda and Boost.Phoenix produce Polymorphic Function Objects i.e. Function objects that can be called with different parameter types and which suppot boost::result_of. In Christ, Steven Watanabe

On 26/03/2011 23:19, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
It's missing a few advantages of Boost.Phoenix-like approaches: - can happen at the expression level and not just statement level. This also means the function does not necessarily need to be named. - does not require listing all variables to bind from the scope - can be quite more concise for simple tasks. There is also the polymorphism thing: functions generated by Boost.Local are necessarily monomorphic, unlike Boost.Phoenix and global functors.

On Sun, May 1, 2011 at 6:46 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 26/03/2011 23:19, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
It's missing a few advantages of Boost.Phoenix-like approaches:
I did try to list these aspects in the comparison table at the beginning of the Alternatives section. Please let me know if it is not clear enough.
- can happen at the expression level and not just statement level. This also means the function does not necessarily need to be named.
This is captured under "Can be defined within expressions". I can add the function naming issue.
- does not require listing all variables to bind from the scope
This is captured under "Bind variables in scope" that for Boost.Lambda reads "No (but variables in scope are accessible as usual within expressions)." and for Boost.Phoenix the same plus "Yes (using let which also allows to bind by constant reference)."
- can be quite more concise for simple tasks.
I think this is arguable but I am providing code examples (actually of simple local functions) so users can judge on their own.
There is also the polymorphism thing: functions generated by Boost.Local are necessarily monomorphic, unlike Boost.Phoenix and global functors.
Do you have a reference for this--like a WiKi page. I don't understand this topic and I'd need to study it more before adding to the docs. Thanks a lot. -- Lorenzo

On 02/05/2011 01:03, Lorenzo Caminiti wrote:
On Sun, May 1, 2011 at 6:46 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 26/03/2011 23:19, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
It's missing a few advantages of Boost.Phoenix-like approaches:
I did try to list these aspects in the comparison table at the beginning of the Alternatives section. Please let me know if it is not clear enough.
- can happen at the expression level and not just statement level. This also means the function does not necessarily need to be named.
This is captured under "Can be defined within expressions". I can add the function naming issue.
I must have been tired if I missed that, sorry.
- does not require listing all variables to bind from the scope
This is captured under "Bind variables in scope" that for Boost.Lambda reads "No (but variables in scope are accessible as usual within expressions)." and for Boost.Phoenix the same plus "Yes (using let which also allows to bind by constant reference)."
That's not what let is for. let is to declare new variables local to the function [*]. All variables in scope are automatically caught as they're accessed with both Boost.Lambda and Boost.Phoenix. It should be Yes for all cases here, and whether the library requires to user to explicitly list all variables or not should be made a separate point. [*] The following Boost.Phoenix code: auto f = let(_a = 42)[_a + _1] is somewhat equivalent to template<typename T> auto f(T&& a1) -> decltype(42 + a1) { auto _a = 42; return _a + std::forward<T>(a1); }
- can be quite more concise for simple tasks.
I think this is arguable but I am providing code examples (actually of simple local functions) so users can judge on their own.
_1 + i vs int BOOST_LOCAL_FUNCTION(int a1, bind int i) { return a1 + i; } BOOST_LOCAL_FUNCTION_NAME(foo); foo Clearly, Boost.Local is more verbose. Boost.Phoenix is better for short and polymorphic stuff, Boost.Local is better for monomorphic, longer and more complex stuff that would be complicated to write with Phoenix.
There is also the polymorphism thing: functions generated by Boost.Local are necessarily monomorphic, unlike Boost.Phoenix and global functors.
Do you have a reference for this--like a WiKi page. I don't understand this topic and I'd need to study it more before adding to the docs. Thanks a lot.
Simply put, the function cannot take its arguments as template parameters, and also requires that the types of the arguments be specified. You might want to know that I plan on proposing allowing template member functions in local classes for a future C++ standard TR (and polymorphic lambdas, too). I think it is of utmost importance to be able to have polymorphic local functions.

Mathias Gaunard-2 wrote:
On 02/05/2011 01:03, Lorenzo Caminiti wrote:
On Sun, May 1, 2011 at 6:46 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 26/03/2011 23:19, Lorenzo Caminiti wrote:
Hello all,
I am updating Boost.Local docs and I could use a some help in getting the Alternatives section right
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
BTW, I have reduced Boost.Phoenix compile-time by #including only the specific headers that I needed: #include <boost/spirit/home/phoenix/statement/sequence.hpp> #include <boost/spirit/home/phoenix/core/reference.hpp> #include <boost/spirit/home/phoenix/core/argument.hpp> #include <boost/spirit/home/phoenix/operator/arithmetic.hpp> Boost.Phoenix still takes longer to compile but the comparison looks better now.
- does not require listing all variables to bind from the scope
This is captured under "Bind variables in scope" that for Boost.Lambda reads "No (but variables in scope are accessible as usual within expressions)." and for Boost.Phoenix the same plus "Yes (using let which also allows to bind by constant reference)."
That's not what let is for. let is to declare new variables local to the function [*]. All variables in scope are automatically caught as they're accessed with both Boost.Lambda and Boost.Phoenix.
It should be Yes for all cases here, and whether the library requires to user to explicitly list all variables or not should be made a separate point.
Yes, I am using let to create a local variable _f that binds factor as a constant reference. Otherwise, variables are accessible as usual within expressions. I have changed the table row title to "Access variables in scope". * For Boost.Phoenix reads "Yes (variables in scope are accessible as usual within expressions). In addition, boost::phoenix::let can be used to bind by constant reference". * For Boost.Lambda reads "Yes (variables in scope are accessible as usual within expressions)". * For Boost.Local it reads "Yes. The variable names are repeated in the function declaration so they can be bound by value, constant value, reference, and constant reference (the object this can also be bound)". * The Local and Global Functor approaches are the only one that cannot access the variables in scope (programmers need to manually create member variables to reference to the variables in scope in this case).
int BOOST_LOCAL_FUNCTION(int a1, bind int i) { return a1 + i; } BOOST_LOCAL_FUNCTION_NAME(foo);
You don't need to specify the bound variable type (that's automatically deduced using Boost.Typeof like Boost.ScopeExit does): int BOOST_LOCAL_FUNCTION(int a1, bind i)
There is also the polymorphism thing: functions generated by Boost.Local are necessarily monomorphic, unlike Boost.Phoenix and global functors.
Do you have a reference for this--like a WiKi page. I don't understand this topic and I'd need to study it more before adding to the docs. Thanks a lot.
Simply put, the function cannot take its arguments as template parameters, and also requires that the types of the arguments be specified.
As I mentioned, Boost.Local does not require to specify the bound variable types (but you do have to specify the types of the normal function parameters). For example: double BOOST_LOCAL_FUNCTION_PARAMS(double num, const bind factor, bind& sum) { BOOST_CONCEPT_ASSERT((Addable<BOOST_LOCAL_TYPEOF(sum)>)); BOOST_CONCEPT_ASSERT((Multiplicable<BOOST_LOCAL_TYPEOF(factor)>)); return sum += factor * num; } BOOST_LOCAL_FUNCTION_NAME(add) Question: Does this make Boost.Local local functions polymorphic in the bound variables but monomorphic in function parameters? (Does this make any sense... I don't know...)
You might want to know that I plan on proposing allowing template member functions in local classes for a future C++ standard TR (and polymorphic lambdas, too). I think it is of utmost importance to be able to have polymorphic local functions.
I also think this feature would be valuable. Do you have any specific use case in mind? Thanks a lot. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 02/05/2011 23:33, lcaminiti wrote:
int BOOST_LOCAL_FUNCTION(int a1, bind int i) { return a1 + i; } BOOST_LOCAL_FUNCTION_NAME(foo);
You don't need to specify the bound variable type (that's automatically deduced using Boost.Typeof like Boost.ScopeExit does):
Ok, but that's still more verbose than the Phoenix version.
Simply put, the function cannot take its arguments as template parameters, and also requires that the types of the arguments be specified.
As I mentioned, Boost.Local does not require to specify the bound variable types
Note I said 'arguments'.
[can bind variable without knowing their type] Question: Does this make Boost.Local local functions polymorphic
No.
I also think this feature would be valuable. Do you have any specific use case in mind?
Parametric polymorphism is a very important property of functional programming. System F, the theory behind the ML family of languages, is polymorphic lambda calculus.

Mathias Gaunard-2 wrote:
On 02/05/2011 23:33, lcaminiti wrote:
Simply put, the function cannot take its arguments as template parameters, and also requires that the types of the arguments be specified.
As I mentioned, Boost.Local does not require to specify the bound variable types
Note I said 'arguments'.
[can bind variable without knowing their type] Question: Does this make Boost.Local local functions polymorphic
No.
I also think this feature would be valuable. Do you have any specific use case in mind?
Parametric polymorphism is a very important property of functional programming. System F, the theory behind the ML family of languages, is polymorphic lambda calculus.
OK, thanks a lot for the clarification! I still don't think I understand this topic well but I am venturing a question... sorry in advance if it doesn't make sense :) For example, it would be useful to program a polymorphic global functor to add a vector of doubles and ints using the same global_add algorithm (without duplicating the code to implement two different algorithms): #include <iostream> #include <vector> #include <algorithm> template<typename T> struct global_add { global_add(double& _sum, const int& _factor): sum(_sum), factor(_factor) {} inline void operator()(T num) { sum += factor * num; } private: double& sum; const int& factor; }; int main() { double sum = 0.0; int factor = 10; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), global_add<double>(sum, factor)); std::vector<int> w(3); w[0] = -1; w[1] = -2; w[2] = -3; std::for_each(w.begin(), w.end(), global_add<int>(sum, factor)); std::cout << sum << std::endl; return 0; } Now, if I want to program this global_add locally within the main() but still retaining its polymorphism in T, I cannot do that using Boost.Local. If I understand it right, that is what makes Boost.Local local function monomorphic in its function argument types. How would I program the polymorphic global_add locally using Boost.Phoenix (or Boost.Lambda)? For example, I think I would need to do something like this (which of course does not compile): int main() { double sum = 0.0; int factor = 10; __some_local_template_type__ local_add = let(_f = cref(factor))[ ref(sum) += _f * _1 ]; std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), local_add<double>(sum, factor)); std::vector<int> w(3); w[0] = -1; w[1] = -2; w[2] = -3; std::for_each(w.begin(), w.end(), local_add<int>(sum, factor)); std::cout << sum << std::endl; return 0; } Note that I'd need to: 1) Program the Boost.Phoenix functor locally within the main() body. 2) Program the Boost.Phoenix functor only once (to avoid code duplication) and then use it on the two different types double and int. Is there a way to do this or something similar with Boost.Phoenix (or Boost.Lambda)? Thanks a lot. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 03/05/2011 21:44, lcaminiti wrote:
For example, it would be useful to program a polymorphic global functor to add a vector of doubles and ints using the same global_add algorithm (without duplicating the code to implement two different algorithms):
Or for more advanced things. Consider a generic algorithm such as fold (accumulate). Now consider another generic algorithm (transform, for_each, whatever) defined in terms of fold. It needs to pass a polymorphic function object to fold in order to be generic.
template<typename T> struct global_add { global_add(double& _sum, const int& _factor): sum(_sum), factor(_factor) {} inline void operator()(T num) { sum += factor * num; } private: double& sum; const int& factor; };
I'd put the template<typename T> on the operator() to avoid having to specify it.
int main() { double sum = 0.0; int factor = 10;
__some_local_template_type__ local_add = let(_f = cref(factor))[ ref(sum) += _f * _1 ];
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), local_add<double>(sum, factor));
std::vector<int> w(3); w[0] = -1; w[1] = -2; w[2] = -3; std::for_each(w.begin(), w.end(), local_add<int>(sum, factor));
std::cout<< sum<< std::endl; return 0; }
Is there a way to do this or something similar with Boost.Phoenix (or Boost.Lambda)?
std::vector<double> v(3); std::for_each(v.begin(), v.end(), ref(sum) += factor * _1); std::vector<int> w(3); std::for_each(w.begin(), w.end(), ref(sum) += factor * _1); or if you want to avoid repetition, auto local_add = ref(sum) += factor * _1; std::vector<double> v(3); std::for_each(v.begin(), v.end(), local_add); std::vector<int> w(3); std::for_each(w.begin(), w.end(), local_add); Note you need auto, since using type erasure would force the function object to be monomorphic.

Mathias Gaunard-2 wrote:
On 03/05/2011 21:44, lcaminiti wrote:
For example, it would be useful to program a polymorphic global functor to add a vector of doubles and ints using the same global_add algorithm (without duplicating the code to implement two different algorithms):
Or for more advanced things. Consider a generic algorithm such as fold (accumulate). Now consider another generic algorithm (transform, for_each, whatever) defined in terms of fold. It needs to pass a polymorphic function object to fold in order to be generic.
I see.
template<typename T> struct global_add { global_add(double& _sum, const int& _factor): sum(_sum), factor(_factor) {} inline void operator()(T num) { sum += factor * num; } private: double& sum; const int& factor; };
I'd put the template<typename T> on the operator() to avoid having to specify it.
Yes, I did think of it but only after I sent the email :)
int main() { double sum = 0.0; int factor = 10;
__some_local_template_type__ local_add = let(_f = cref(factor))[ ref(sum) += _f * _1 ];
std::vector<double> v(3); v[0] = 1.0; v[1] = 2.0; v[2] = 3.0; std::for_each(v.begin(), v.end(), local_add<double>(sum, factor));
std::vector<int> w(3); w[0] = -1; w[1] = -2; w[2] = -3; std::for_each(w.begin(), w.end(), local_add<int>(sum, factor));
std::cout<< sum<< std::endl; return 0; }
Is there a way to do this or something similar with Boost.Phoenix (or Boost.Lambda)?
std::vector<double> v(3); std::for_each(v.begin(), v.end(), ref(sum) += factor * _1);
std::vector<int> w(3); std::for_each(w.begin(), w.end(), ref(sum) += factor * _1);
or if you want to avoid repetition,
auto local_add = ref(sum) += factor * _1;
std::vector<double> v(3); std::for_each(v.begin(), v.end(), local_add);
std::vector<int> w(3); std::for_each(w.begin(), w.end(), local_add);
Note you need auto, since using type erasure would force the function object to be monomorphic.
Can I do this without auto? Otherwise, the local Phoenix function retains its polymorphic behavior only on C++0x (but not on ISO C++) when it is given a name by assigning it to a local variable like local_add. Thanks a lot again. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 05/04/2011 11:43 AM, lcaminiti wrote: [snip]
Can I do this without auto? Otherwise, the local Phoenix function retains its polymorphic behavior only on C++0x (but not on ISO C++) when it is given a name by assigning it to a local variable like local_add.
auto naturally makes it more convenient in many cases (and note that even with C++1x, phoenix retains the advantage of polymorphism over C++1x lambdas). However, in many cases a template function may take as a parameter an explicitly polymorphic function object, e.g. the various transformation functions of Boost.Fusion, or the visitor functions of Boost.Variant.

On 04/05/2011 20:43, lcaminiti wrote:
Can I do this without auto?
Not if you want to define the function object in a local scope.
Otherwise, the local Phoenix function retains its polymorphic behavior only on C++0x (but not on ISO C++)
Note a lot of C++03 compilers provide typeof which is basically the same thing, and it can be implemented on MSVC exploiting a bug. So you can write BOOST_AUTO(f, ref(sum) += factor * _1); and it's pretty portable. Actually, Boost.Phoenix uses Proto, which itself requires native support of Boost.Typeof.

Mathias Gaunard-2 wrote:
On 03/05/2011 21:44, lcaminiti wrote:
Is there a way to do this or something similar with Boost.Phoenix (or Boost.Lambda)?
std::vector<double> v(3); std::for_each(v.begin(), v.end(), ref(sum) += factor * _1);
std::vector<int> w(3); std::for_each(w.begin(), w.end(), ref(sum) += factor * _1);
or if you want to avoid repetition,
auto local_add = ref(sum) += factor * _1;
std::vector<double> v(3); std::for_each(v.begin(), v.end(), local_add);
std::vector<int> w(3); std::for_each(w.begin(), w.end(), local_add);
Note you need auto, since using type erasure would force the function object to be monomorphic.
I think I can do this also without auto so it compiles on ISO C++. The following works (even if the type expression that replaces auto is very ugly -- perfect example of why C++0x's auto is useful): #include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector> int main() { using boost::phoenix::arg_names::_1; boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::shift_left_eval, boost::fusion::vector<boost::phoenix::composite<boost::phoenix::shift_left_eval, boost::fusion::vector<boost::phoenix::reference<std::basic_ostream<char, std::char_traits<char> > >, boost::phoenix::argument<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, boost::phoenix::value<const char*>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > f = std::cout << _1 << "\n"; std::vector<double> v(3); v[0] = -1.0; v[1] = -2.0; v[2] = -3.0; std::for_each(v.begin(), v.end(), f); std::vector<std::string> s(3); s[0] = "aa"; s[1] = "bb"; s[2] = "cc"; std::for_each(s.begin(), s.end(), f); return 0; } This does what I was looking for: 1) Compiles on ISO C++. 2) Declares f locally (information hiding). 3) Does not repeat f declaration multiple times (avoid code duplication). 4) f is polymorphic in its argument type _1 (it accepts both doubles and std::strings). I am thinking that I will add the monomorphic (Boost.Local, Local Functors, and C++0x lambdas*) vs. polymorphic (Boost.Phoenix, Boost.Local, and Global Functors) comparison to the Alternatives section. (*) BTW, as I understand it, C++0x lambdas are monomorphic in their argument types -- correct? Thanks. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

lcaminiti wrote:
Mathias Gaunard-2 wrote:
On 03/05/2011 21:44, lcaminiti wrote:
Is there a way to do this or something similar with Boost.Phoenix (or Boost.Lambda)?
std::vector<double> v(3); std::for_each(v.begin(), v.end(), ref(sum) += factor * _1);
std::vector<int> w(3); std::for_each(w.begin(), w.end(), ref(sum) += factor * _1);
or if you want to avoid repetition,
auto local_add = ref(sum) += factor * _1;
std::vector<double> v(3); std::for_each(v.begin(), v.end(), local_add);
std::vector<int> w(3); std::for_each(w.begin(), w.end(), local_add);
Note you need auto, since using type erasure would force the function object to be monomorphic.
I think I can do this also without auto so it compiles on ISO C++. The following works (even if the type expression that replaces auto is very ugly -- perfect example of why C++0x's auto is useful):
#include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <vector>
int main() { using boost::phoenix::arg_names::_1;
boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::shift_left_eval, boost::fusion::vector<boost::phoenix::composite<boost::phoenix::shift_left_eval, boost::fusion::vector<boost::phoenix::reference<std::basic_ostream<char, std::char_traits<char> > >, boost::phoenix::argument<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, boost::phoenix::value<const char*>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > f = std::cout << _1 << "\n";
std::vector<double> v(3); v[0] = -1.0; v[1] = -2.0; v[2] = -3.0; std::for_each(v.begin(), v.end(), f);
std::vector<std::string> s(3); s[0] = "aa"; s[1] = "bb"; s[2] = "cc"; std::for_each(s.begin(), s.end(), f);
return 0; }
This does what I was looking for: 1) Compiles on ISO C++. 2) Declares f locally (information hiding). 3) Does not repeat f declaration multiple times (avoid code duplication). 4) f is polymorphic in its argument type _1 (it accepts both doubles and std::strings).
I am thinking that I will add the monomorphic (Boost.Local, Local Functors, and C++0x lambdas*) vs. polymorphic (Boost.Phoenix, Boost.Local, and Global Functors) comparison to the Alternatives section.
(*) BTW, as I understand it, C++0x lambdas are monomorphic in their argument types -- correct?
I have been thinking if I can do something similar to this with Boost.Local. Given that local classes cannot have template members I can't do too much... However, I _could_ allow to specify multiple types (but not a generic type) for a local function parameter: void BOOST_LOCAL_FUNCTION_PARAMS(types(int, char) x, types(double, std::string, int) y, long z) { std::cout << x << y << z << std::endl; } BOOST_LOCAL_FUNCTION_NAME(l) Then I can do: l(1, 1.2, -1); l('a', 1.2, -1); l('a', "bcd", -1); ... // and all the other parameter type combinations types(...) could accept a generic number of types but all these types will have to be known (and not generic as for templates). With this, the Boost.Phoenix example above will look like the following in Boost.Local: #include <boost/local/fuction.hpp> #include <iostream> #include <vector> #include <algorithm> int main() { void BOOST_LOCAL_FUNCTION_PARAMS( // Accepts both double and std::string. types(const double&, const std::string&) num) { std::cout << num << std::endl; } BOOST_LOCAL_FUNCTION_NAME(l) std::vector<double> v(3); v[0] = -1.0; v[1] = -2.0; v[2] = -3.0; std::for_each(v.begin(), v.end(), l); // Call passing double. std::vector<std::string> s(3); s[0] = "aa"; s[1] = "bb"; s[2] = "cc"; std::for_each(s.begin(), s.end(), l); // Call passing std::string. return 0; } This is more overloading than polymorphism... bus still: 1) Compiles on ISO C++. 2) Declares l locally (information hiding). 3) Does not repeat l declaration multiple times (avoid code duplication). 4) l is """effectively polymorphic""" (in between _many_ quotes :) ) in its argument type num as it accepts both doubles and std::strings (but no more than these two types :( ). (I will not actually claim that such a local function l polymorphic in num's type.) What do you think? Thanks, --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Thu, May 5, 2011 at 10:53 AM, lcaminiti <lorcaminiti@gmail.com> wrote: [...]
I have been thinking if I can do something similar to this with Boost.Local. Given that local classes cannot have template members I can't do too much... However, I _could_ allow to specify multiple types (but not a generic type) for a local function parameter:
void BOOST_LOCAL_FUNCTION_PARAMS(types(int, char) x, types(double, std::string, int) y, long z) { std::cout << x << y << z << std::endl; } BOOST_LOCAL_FUNCTION_NAME(l)
Then I can do:
l(1, 1.2, -1); l('a', 1.2, -1); l('a', "bcd", -1); ... // and all the other parameter type combinations
types(...) could accept a generic number of types but all these types will have to be known (and not generic as for templates).
[...]
This is more overloading than polymorphism... bus still: 1) Compiles on ISO C++. 2) Declares l locally (information hiding). 3) Does not repeat l declaration multiple times (avoid code duplication). 4) l is """effectively polymorphic""" (in between _many_ quotes :) ) in its argument type num as it accepts both doubles and std::strings (but no more than these two types :( ). (I will not actually claim that such a local function l polymorphic in num's type.)
What do you think?
Better than nothing (=strict monomorphicity)! I would assume the types(...) syntax is only optional, correct? Not related to the above discussion: Bound variables' types are deduced using Boost.TypeOf; is it possible right now to explicitly specify their type? - Jeff

On Thu, May 5, 2011 at 2:03 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
On Thu, May 5, 2011 at 10:53 AM, lcaminiti <lorcaminiti@gmail.com> wrote: [...]
I have been thinking if I can do something similar to this with Boost.Local. Given that local classes cannot have template members I can't do too much... However, I _could_ allow to specify multiple types (but not a generic type) for a local function parameter:
void BOOST_LOCAL_FUNCTION_PARAMS(types(int, char) x, types(double, std::string, int) y, long z) { std::cout << x << y << z << std::endl; } BOOST_LOCAL_FUNCTION_NAME(l)
Then I can do:
l(1, 1.2, -1); l('a', 1.2, -1); l('a', "bcd", -1); ... // and all the other parameter type combinations
types(...) could accept a generic number of types but all these types will have to be known (and not generic as for templates).
[...]
This is more overloading than polymorphism... bus still: 1) Compiles on ISO C++. 2) Declares l locally (information hiding). 3) Does not repeat l declaration multiple times (avoid code duplication). 4) l is """effectively polymorphic""" (in between _many_ quotes :) ) in its argument type num as it accepts both doubles and std::strings (but no more than these two types :( ). (I will not actually claim that such a local function l polymorphic in num's type.)
What do you think?
Better than nothing (=strict monomorphicity)!
Does anyone else think this feature is useful?? This is _not_ trivial to implement so I won't do it unless you guys think it is useful. I might just document it as a possibility in the docs and implement it only if the library gets accepted... The macros will have to expand to something like this: #include <iostream> #include <vector> #include <algorithm> template<typename T1 = void, typename T2 = void, typename T3 = void> struct types {}; template<typename F> struct func {}; template<typename R, typename A1> struct func<R (A1)> { typedef R (*call_ptr)(void*, A1); func(void* obj, call_ptr call): obj_(obj), call_(call) {} R operator()(A1 a1) { return call_(obj_, a1); } private: void* obj_; call_ptr call_; }; template<typename R, typename A1T1, typename A1T2> struct func<R (types<A1T1, A1T2>)> { typedef R (*call_a1t1_ptr)(void*, A1T1); typedef R (*call_a1t2_ptr)(void*, A1T2); func(void* obj, call_a1t1_ptr call_a1t1, call_a1t2_ptr call_a1t2): obj_(obj), call_a1t1_(call_a1t1), call_a1t2_(call_a1t2) {} R operator()(A1T1 a1t1) { return call_a1t1_(obj_, a1t1); } R operator()(A1T2 a1t2) { return call_a1t2_(obj_, a1t2); } private: void* obj_; call_a1t1_ptr call_a1t1_; call_a1t2_ptr call_a1t2_; }; int main() { // void BOOST_LOCAL_FUNCTION(types(const double&, const std::string&) num, // const bind& sep, { // std::cout << num << std::endl; // }) BOOST_LOCAL_FUNCTION_NAME(l) char sep = '\n'; struct local { local(const char& sep): sep_(sep) {} void operator()(double num) { body(sep_, num); } static void call(void* obj, double num) { (*static_cast<local*>(obj))(num); } void operator()(std::string num) { body(sep_, num); } static void call(void* obj, std::string num) { (*static_cast<local*>(obj))(num); } private: const char& sep_; void body(const char& sep, double num) { std::cout << num << std::endl; } void body(const char& sep, std::string num) { std::cout << num << std::endl; } } local_l(sep); func<void (types<double, std::string>)> l(&local_l, local_l.call, local_l.call); std::vector<double> v(3); v[0] = -1.0; v[1] = -2.0; v[2] = -3.0; std::for_each(v.begin(), v.end(), l); l(0); std::vector<std::string> s(3); s[0] = "aa"; s[1] = "bb"; s[2] = "cc"; std::for_each(s.begin(), s.end(), l); l("zz"); return 0; } Note that the macro will have to expand the body in multiple places (using automatic code repetition because I can't use generic types) so the body will have to be passed at a macro parameter: void BOOST_LOCAL_FUNCTION(types(const double&, const std::string&) num, const bind& sep, { // (1) std::cout << num << std::endl; }) BOOST_LOCAL_FUNCTION_NAME(l) The macro will take the body as its last parameter but only when types() is used. If types() is not used the body will still be outside the macro (I'd rename BOOST_LOCAL_FUNCTION_PARAMS to BOOST_LOCAL_FUNCTION because the macro sometimes also takes the body as one of its parameters): void BOOST_LOCAL_FUNCTION(const double& num, const bind& sep) { // unchanged syntax std::cout << num << std::endl; } BOOST_LOCAL_FUNCTION_NAME(l) Passing the body code as a macro parameter when types() is used as in (1) will cause all compiler errors to have the same line number -- that's a major inconvenience.
I would assume the types(...) syntax is only optional, correct?
Yes, types() is optional. If types() is not used for any of the function parameters then the syntax of the macros remains the same as the one we discussed so far (including the body being outside the macro). So you can do: int x // no types() (body specified outside the FUNCTION macro) types(int) x // same as above so not very useful (body specified inside the FUNCTION macro) types(int, std::string, const std::vector<double>&) x // x can be of multiple types but not of a generic type (body specified inside the FUNCTION macro).
Not related to the above discussion: Bound variables' types are deduced using Boost.TypeOf; is it possible right now to explicitly specify their type?
Yes, I think either you or someone else already asked for this feature a while back. It's on my to-dos and I will implement it before submitting the library for review. I am trying to get this syntax to work but it's requiring good amount of coordination between preprocessor and template metaprogramming (I haven't given up yet :) ): const bind& x // bind without specifying the type (uses Boost.Typeof) const bind<int>& x // bind specifying the type (doesn't use Boost.Typeof) If I can't get that to work, the following should be possible without too much trouble (because I can handle both expression the same way and just with preprocessor metaprogramming): const bind& x // bind without specifying the type (uses Boost.Typeof) const bind_type(int)& x // bind specifying the type (doesn't use Boost.Typeof) -- Lorenzo

On 05/06/2011 07:49 AM, Lorenzo Caminiti wrote:
Does anyone else think this feature is useful??
This is _not_ trivial to implement so I won't do it unless you guys think it is useful. I might just document it as a possibility in the docs and implement it only if the library gets accepted...
I don't think it is worth implementing.

On Fri, May 6, 2011 at 7:49 AM, Lorenzo Caminiti <lorcaminiti@gmail.com>wrote:
On Thu, May 5, 2011 at 2:03 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
On Thu, May 5, 2011 at 10:53 AM, lcaminiti <lorcaminiti@gmail.com> wrote: [...]
I have been thinking if I can do something similar to this with Boost.Local. Given that local classes cannot have template members I can't do too much... However, I _could_ allow to specify multiple types (but not a generic type) for a local function parameter:
void BOOST_LOCAL_FUNCTION_PARAMS(types(int, char) x, types(double, std::string, int) y, long z) { std::cout << x << y << z << std::endl; } BOOST_LOCAL_FUNCTION_NAME(l)
Then I can do:
l(1, 1.2, -1); l('a', 1.2, -1); l('a', "bcd", -1); ... // and all the other parameter type combinations
types(...) could accept a generic number of types but all these types will have to be known (and not generic as for templates).
[...]
This is more overloading than polymorphism... bus still: 1) Compiles on ISO C++. 2) Declares l locally (information hiding). 3) Does not repeat l declaration multiple times (avoid code duplication). 4) l is """effectively polymorphic""" (in between _many_ quotes :) ) in its argument type num as it accepts both doubles and std::strings (but no more than these two types :( ). (I will not actually claim that such a local function l polymorphic in num's type.)
What do you think?
Better than nothing (=strict monomorphicity)!
Does anyone else think this feature is useful??
This is _not_ trivial to implement so I won't do it unless you guys think it is useful. I might just document it as a possibility in the docs and implement it only if the library gets accepted...
Although it *is* "better than nothing", I wouldn't consider this a necessity, whether or not it's easy to implement. [...]
Not related to the above discussion: Bound variables' types are deduced using Boost.TypeOf; is it possible right now to explicitly specify their type?
Yes, I think either you or someone else already asked for this feature a while back. It's on my to-dos and I will implement it before submitting the library for review.
Excellent. Yes, it was probably me.
I am trying to get this syntax to work but it's requiring good amount of coordination between preprocessor and template metaprogramming (I haven't given up yet :) ):
const bind& x // bind without specifying the type (uses Boost.Typeof) const bind<int>& x // bind specifying the type (doesn't use Boost.Typeof)
If I can't get that to work, the following should be possible without too much trouble (because I can handle both expression the same way and just with preprocessor metaprogramming):
const bind& x // bind without specifying the type (uses Boost.Typeof) const bind_type(int)& x // bind specifying the type (doesn't use Boost.Typeof)
Would "const bind(int)& x" work? If not, and assuming "const bind<int>& x" also doesn't work, "bind_type(int)" sounds like an acceptable alternative. - Jeff

On Fri, May 6, 2011 at 1:32 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
Would "const bind(int)& x" work?
If not, and assuming "const bind<int>& x" also doesn't work, "bind_type(int)" sounds like an acceptable alternative.
I need to experiment with all these alternatives more before I can try to comment intelligently. I will let you know (and document everything in the docs' Rationale). -- Lorenzo

On Fri, May 6, 2011 at 2:07 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Fri, May 6, 2011 at 1:32 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
Would "const bind(int)& x" work?
It think yes :) I should be able to support the syntax (also with optional leading const and optional &): bind& x // deduced type (with Boost.Typeof) bind(int)& x // specify type (no Boost.Typeof) More in general "[const] bind [(type)] [&] name" where "[t]" indicates that token t is optional. The basic internal preprocessor tools for that should be: #include <boost/local/aux_/preprocessor/keyword/bind.hpp> #include <boost/preprocessor.hpp> #include <boost/preprocessor/detail/is_unary.hpp> #define IS_BIND_TYPED_(tokens) \ BOOST_PP_IS_UNARY(BOOST_LOCAL_AUX_PP_KEYWORD_BIND_REMOVE_FRONT(tokens)) #define IS_BIND_TYPED(tokens) \ BOOST_PP_IIF(BOOST_LOCAL_AUX_PP_KEYWORD_IS_BIND_FRONT(tokens), \ IS_BIND_TYPED_ \ , \ 0 BOOST_PP_TUPLE_EAT(1) \ )(tokens) #define BIND_TYPED_EXPR_bind(type) \ type #define BIND_TYPED_EXPR_(tokens) \ BOOST_PP_CAT(BIND_TYPED_EXPR_, tokens) #define BIND_TYPED_EXPR(tokens) \ BOOST_PP_IIF(IS_BIND_TYPED(tokens), \ BIND_TYPED_EXPR_ \ , \ tokens BOOST_PP_TUPLE_EAT(1) \ )(tokens) #define BIND_TYPED_REMOVE_FRONT_bind(tokens) /* must expand to nothing */ #define BIND_TYPED_REMOVE_FRONT_(tokens) \ BOOST_PP_CAT(BIND_TYPED_REMOVE_FRONT_, tokens) #define BIND_TYPED_REMOVE_FRONT(tokens) \ BOOST_PP_IIF(IS_BIND_TYPED(tokens), \ BIND_TYPED_REMOVE_FRONT_ \ , \ tokens BOOST_PP_TUPLE_EAT(1) \ )(tokens) ----- IS_BIND_TYPED( int& x ) // 0 IS_BIND_TYPED( bind& x ) // 0 IS_BIND_TYPED( bind(double)& x ) // 1 ----- BIND_TYPED_EXPR( int& x ) // int& x BIND_TYPED_EXPR( bind& x ) // bind& x BIND_TYPED_EXPR( bind(double)& x ) // double& x ----- BIND_TYPED_REMOVE_FRONT( int& x ) // int& x BIND_TYPED_REMOVE_FRONT( bind& x ) // bind& x BIND_TYPED_REMOVE_FRONT( bind(double)& x ) // &x ----- -- Lorenzo

On Fri, May 6, 2011 at 7:59 PM, Lorenzo Caminiti <lorcaminiti@gmail.com>wrote:
On Fri, May 6, 2011 at 2:07 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Fri, May 6, 2011 at 1:32 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
Would "const bind(int)& x" work?
It think yes :) I should be able to support the syntax (also with optional leading const and optional &):
bind& x // deduced type (with Boost.Typeof) bind(int)& x // specify type (no Boost.Typeof)
More in general "[const] bind [(type)] [&] name" where "[t]" indicates that token t is optional.
[...snip preprocessor details...] Awesome. - Jeff

Jeffrey Lee Hellrung, Jr.-2 wrote:
On Fri, May 6, 2011 at 7:59 PM, Lorenzo Caminiti <lorcaminiti@gmail.com>wrote:
On Fri, May 6, 2011 at 2:07 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Fri, May 6, 2011 at 1:32 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
Would "const bind(int)& x" work?
It think yes :) I should be able to support the syntax (also with optional leading const and optional &):
bind& x // deduced type (with Boost.Typeof) bind(int)& x // specify type (no Boost.Typeof)
More in general "[const] bind [(type)] [&] name" where "[t]" indicates that token t is optional.
[...snip preprocessor details...]
Awesome.
I have implemented this: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... #include <boost/local/function.hpp> #include <boost/local/block.hpp> #include <boost/local/exit.hpp> #include <vector> #include <algorithm> #include <iostream> #include <sstream> #include <cassert> class adder { public: adder(): sum_(0.0) {} double sum(const std::vector<double>& nums, const int& factor = 10) { std::ostringstream out; void BOOST_LOCAL_FUNCTION_PARAMS(double num, const bind(const int&) factor, // Specify bind types bind(std::ostringstream)& out, // explicitly (so no bind(adder*) this) { // Boost.Typeof for binds). this_->sum_ += factor * num; out << "Summed: " << this_->sum_ << std::endl; } BOOST_LOCAL_FUNCTION_NAME(add) std::for_each(nums.begin(), nums.end(), add); BOOST_LOCAL_EXIT(const bind(std::ostringstream)& out) { std::cout << out.str(); } BOOST_LOCAL_EXIT_END BOOST_LOCAL_BLOCK(bind(std::ostringstream)& out, const bind(adder*) this) { out << "Asserted: " << this_->sum_ << std::endl; assert(this_->sum_ > 0.0); } BOOST_LOCAL_BLOCK_END return sum_; } private: double sum_; }; int main() { std::vector<double> v(3); v[0] = 100.0; v[1] = 90.5; v[2] = 7.0; adder a; // sum = 10 * 100.0 + 10 * 90.5 + 10 * 7.0 = 1975.0 assert(a.sum(v) == 1975.0); return 0; } --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Thu, May 12, 2011 at 9:05 AM, lcaminiti <lorcaminiti@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr.-2 wrote:
On Fri, May 6, 2011 at 7:59 PM, Lorenzo Caminiti <lorcaminiti@gmail.com>wrote:
On Fri, May 6, 2011 at 2:07 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Fri, May 6, 2011 at 1:32 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
Would "const bind(int)& x" work?
It think yes :) I should be able to support the syntax (also with optional leading const and optional &):
bind& x // deduced type (with Boost.Typeof) bind(int)& x // specify type (no Boost.Typeof)
More in general "[const] bind [(type)] [&] name" where "[t]" indicates that token t is optional.
[...snip preprocessor details...]
Awesome.
I have implemented this:
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
Great! Looks like a typo in the 4th bind use case: const bind(variable-type)& variable-name // Bind by constant value with explicit type. Should be "...by reference-to-const..." or "...by constant reference..." (depending on how you refer to such references throughout the documentation), eh?
#include <boost/local/function.hpp> #include <boost/local/block.hpp> #include <boost/local/exit.hpp> #include <vector> #include <algorithm> #include <iostream> #include <sstream> #include <cassert>
class adder { public: adder(): sum_(0.0) {}
double sum(const std::vector<double>& nums, const int& factor = 10) { std::ostringstream out;
void BOOST_LOCAL_FUNCTION_PARAMS(double num, const bind(const int&) factor, // Specify bind types bind(std::ostringstream)& out, // explicitly (so no
I would infer from this and the documentation that const bind(const int&) factor // outer const superfluous??? bind(const int&) factor const bind(const int)& factor // outer const superfluous??? bind(const int)& factor const bind(int)& factor bind(const int&) const factor // outer const superfluous??? bind(int) const & factor are all equivalent, but I'm not sure. Can you please clarify in the documentation? [...snip rest of example...] - Jeff

Jeffrey Lee Hellrung, Jr.-2 wrote:
On Thu, May 12, 2011 at 9:05 AM, lcaminiti <lorcaminiti@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr.-2 wrote:
On Fri, May 6, 2011 at 7:59 PM, Lorenzo Caminiti <lorcaminiti@gmail.com>wrote:
On Fri, May 6, 2011 at 2:07 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Fri, May 6, 2011 at 1:32 PM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
Would "const bind(int)& x" work?
It think yes :) I should be able to support the syntax (also with optional leading const and optional &):
bind& x // deduced type (with Boost.Typeof) bind(int)& x // specify type (no Boost.Typeof)
More in general "[const] bind [(type)] [&] name" where "[t]" indicates that token t is optional.
[...snip preprocessor details...]
Awesome.
I have implemented this:
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
Great!
Looks like a typo in the 4th bind use case:
const bind(variable-type)& variable-name // Bind by constant value with explicit type.
Should be "...by reference-to-const..." or "...by constant reference..." (depending on how you refer to such references throughout the documentation), eh?
Yep, a cut-n-paste error :) It should say "Bind by constant reference with explicit type". I fixed it -- thanks for catching it.
I would infer from this and the documentation that
const bind(const int&) factor // outer const superfluous??? bind(const int&) factor const bind(const int)& factor // outer const superfluous??? bind(const int)& factor const bind(int)& factor bind(const int&) const factor // outer const superfluous??? bind(int) const & factor
are all equivalent, but I'm not sure. Can you please clarify in the documentation?
[...snip rest of example...]
Yes, the Tutorial section already mentions that: 1) const must always appear before bind when constant binding is used so bind ... const is not valid (this is just for simplicity, the macros could be programmed to accepts both const bind and bind const). 2) when const bind is used on a variable that is already const the bind's const has no effect. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Thu, May 12, 2011 at 11:16 AM, lcaminiti <lorcaminiti@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr.-2 wrote:
[...]
I would infer from this and the documentation that
const bind(const int&) factor // outer const superfluous??? bind(const int&) factor const bind(const int)& factor // outer const superfluous??? bind(const int)& factor const bind(int)& factor bind(const int&) const factor // outer const superfluous??? bind(int) const & factor
are all equivalent, but I'm not sure. Can you please clarify in the documentation?
[...snip rest of example...]
Yes, the Tutorial section already mentions that: 1) const must always appear before bind when constant binding is used so bind ... const is not valid (this is just for simplicity, the macros could be programmed to accepts both const bind and bind const). 2) when const bind is used on a variable that is already const the bind's const has no effect.
So that addresses the placement of const; the '&' can also either be put inside or outside the bind(...), right? Also, what about commas from template instantiations? E.g., does bind(tmpl<T1,T2>) x work? - Jeff

Jeffrey Lee Hellrung, Jr.-2 wrote:
On Thu, May 12, 2011 at 11:16 AM, lcaminiti <lorcaminiti@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr.-2 wrote:
[...]
I would infer from this and the documentation that
const bind(const int&) factor // outer const superfluous??? bind(const int&) factor const bind(const int)& factor // outer const superfluous??? bind(const int)& factor const bind(int)& factor bind(const int&) const factor // outer const superfluous??? bind(int) const & factor
are all equivalent, but I'm not sure. Can you please clarify in the documentation?
[...snip rest of example...]
Yes, the Tutorial section already mentions that: 1) const must always appear before bind when constant binding is used so bind ... const is not valid (this is just for simplicity, the macros could be programmed to accepts both const bind and bind const). 2) when const bind is used on a variable that is already const the bind's const has no effect.
So that addresses the placement of const; the '&' can also either be put inside or outside the bind(...), right?
No. References are bound be value when bind is used without the trailing &: int y = 0; int& x = y BOOST_LOCAL_BLOCK(bind x) { // by val x = 0; // Has only local effect (outer x and y are not changed). } BOOST_LOCAL_BLOCK(bind& x) { // by ref x = 0; // Has effect on enclosing scope (outer x and y are changed). } This is how Boost.ScopeExit bind semantic works and it made sense to me because it allows to bind references by both value and reference (and not just by reference). I can spell this out more clearly in the docs. OTOH, const is never stripped by bind because if a variable is const in the enclosing scope, programmers would expect it to be always const also in at local scopes: const int x = 10; BOOST_LOCAL_BLOCK(bind& x) { // (1) by const& x = -1; // This should always error even when const bind was not used. } BOOST_LOCAL_BLOCK(const bind& x) { // (2) also by const& (equivalent to above) x = -1; // Also error. } Of course Boost.Local could strip the const in case (1) (using const_cast) but I would find it confusing that a const is no longer const because it is not bind by constant.
Also, what about commas from template instantiations? E.g., does
bind(tmpl<T1,T2>) x
work?
Yes but you have to use BOOST_IDENTITY_TYPE (its a macro of Boost.Local that I'd eventually propose to add to under boost/utility). It's explained in the Advanced Topics section: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... For example: bind(BOOST_IDENTITY_TYPE((std::map<std::string, double>))) x This works (on ISO C++, no variadics required). Note the extra set of parenthesis needed around the type-with-commas within the macro parenthesis BOOST_IDENTITY_TYPE((type_with_commas)) -- it expands to something like function_traits<void(type_with_commas)>::arg1_type. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Thu, May 12, 2011 at 12:05 PM, lcaminiti <lorcaminiti@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr.-2 wrote:
On Thu, May 12, 2011 at 11:16 AM, lcaminiti <lorcaminiti@gmail.com
>
wrote:
Jeffrey Lee Hellrung, Jr.-2 wrote:
[...]
I would infer from this and the documentation that
const bind(const int&) factor // outer const superfluous??? bind(const int&) factor const bind(const int)& factor // outer const superfluous??? bind(const int)& factor const bind(int)& factor bind(const int&) const factor // outer const superfluous??? bind(int) const & factor
are all equivalent, but I'm not sure. Can you please clarify in the documentation?
[...snip rest of example...]
Yes, the Tutorial section already mentions that: 1) const must always appear before bind when constant binding is used so bind ... const is not valid (this is just for simplicity, the macros could be programmed to accepts both const bind and bind const). 2) when const bind is used on a variable that is already const the bind's const has no effect.
So that addresses the placement of const; the '&' can also either be put inside or outside the bind(...), right?
No. References are bound be value when bind is used without the trailing &:
int y = 0; int& x = y BOOST_LOCAL_BLOCK(bind x) { // by val x = 0; // Has only local effect (outer x and y are not changed). } BOOST_LOCAL_BLOCK(bind& x) { // by ref x = 0; // Has effect on enclosing scope (outer x and y are changed). }
This is how Boost.ScopeExit bind semantic works and it made sense to me because it allows to bind references by both value and reference (and not just by reference). I can spell this out more clearly in the docs.
I meant to explicitly ask whether the following are equivalent: bind(T)& x bind(T&) x [...]
Also, what about commas from template instantiations? E.g., does
bind(tmpl<T1,T2>) x
work?
Yes but you have to use BOOST_IDENTITY_TYPE (its a macro of Boost.Local that I'd eventually propose to add to under boost/utility). It's explained in the Advanced Topics section:
http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local...
For example:
bind(BOOST_IDENTITY_TYPE((std::map<std::string, double>))) x
This works (on ISO C++, no variadics required). Note the extra set of parenthesis needed around the type-with-commas within the macro parenthesis BOOST_IDENTITY_TYPE((type_with_commas)) -- it expands to something like function_traits<void(type_with_commas)>::arg1_type.
Sounds good. - Jeff

Jeffrey Lee Hellrung, Jr.-2 wrote:
I meant to explicitly ask whether the following are equivalent:
bind(T)& x bind(T&) x
[...]
No, they are not. bind(T)& x binds by reference so a change to x within the local scope will reflect to x in the enclosing scope. bind(T&) x binds by value so a change to x within the local scope will /not/ reflect to x in the enclosing scope. int x = 0; int& r = x; int y = 0; int& s = y; BOOST_LOCAL_BLOCK(bind(int&) r, bind(int&)& s) { // Only s bind by ref. r = -1; // Does not affect enclosing scope. s = -1; // Affects enclosing scope. } BOOST_LOCAL_BLOCK_END assert(r == 0); // Not changed by local block. assert(s == -1); // Changed by local block. In bind(T&)& the outer reference is the one that applies to the variable binding. The inner reference only indicates what the original variable type is. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Sun, May 1, 2011 at 6:46 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
There is also the polymorphism thing: functions generated by Boost.Local are necessarily monomorphic, unlike Boost.Phoenix and global functors.
On Fri, May 6, 2011 at 10:49 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
void BOOST_LOCAL_FUNCTION(types(const double&, const std::string&) num, const bind& sep, { // (1) std::cout << num << std::endl; }) BOOST_LOCAL_FUNCTION_NAME(l)
l(1.23); l("abc");
This is more overloading than polymorphism... bus still: 1) Compiles on ISO C++. 2) Declares l locally (information hiding). 3) Does not repeat l declaration multiple times (avoid code duplication). 4) l is """effectively polymorphic""" (in between _many_ quotes :) ) in its argument type num as it accepts both doubles and std::strings (but no more than these two types :( ). (I will not actually claim that such a local function l polymorphic in num's type.)
Does anyone else think this feature is useful??
This is _not_ trivial to implement so I won't do it unless you guys think it is useful. I might just document it as a possibility in the docs and implement it only if the library gets accepted...
Hello Mathias, I'm curious if you have an opinion about the usefulness of Boost.Local supporting multiple types (but not generic types) for its function parameters. Thank you very much. -- Lorenzo

On 07/05/2011 18:00, Lorenzo Caminiti wrote:
Hello Mathias, I'm curious if you have an opinion about the usefulness of Boost.Local supporting multiple types (but not generic types) for its function parameters.
Probably not worth the effort, it seems that it would be a lot of work. And you can still have overloading by doing it like this: void BOOST_LOCAL_FUNCTION(const double& num, const bind& sep) std::cout << num << std::endl; BOOST_LOCAL_FUNCTION_NAME(l1) void BOOST_LOCAL_FUNCTION(const std::string& num, const bind& sep) std::cout << num << std::endl; BOOST_LOCAL_FUNCTION_NAME(l2) auto /* or the real type */ l = overload(l1, l2);

On Sun, May 8, 2011 at 5:02 AM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 07/05/2011 18:00, Lorenzo Caminiti wrote:
Hello Mathias, I'm curious if you have an opinion about the usefulness of Boost.Local supporting multiple types (but not generic types) for its function parameters.
Probably not worth the effort, it seems that it would be a lot of work.
And you can still have overloading by doing it like this:
void BOOST_LOCAL_FUNCTION(const double& num, const bind& sep) std::cout << num << std::endl; BOOST_LOCAL_FUNCTION_NAME(l1)
void BOOST_LOCAL_FUNCTION(const std::string& num, const bind& sep) std::cout << num << std::endl; BOOST_LOCAL_FUNCTION_NAME(l2)
auto /* or the real type */ l = overload(l1, l2);
Does Boost already have a functor overloader like overload() above? If not, I can add something like overload<> below to Boost.Local: #include <boost/local/function.hpp> #include <boost/function.hpp> #include <vector> #include <algorithm> #include <iostream> #include <string> template<typename F0, typename F1, typename F2 = void, typename F3 = void> struct overload { }; template<typename F0R, typename F0A0, typename F1R, typename F1A0> struct overload<F0R (F0A0), F1R (F1A0)> { overload(boost::function<F0R (F0A0)> f0, boost::function<F1R (F1A0)> f1): f0_(f0), f1_(f1) {} F0R operator()(F0A0 a0) const { return f0_(a0); } F1R operator()(F1A0 a0) const { return f1_(a0); } private: boost::function<F0R (F0A0)> f0_; boost::function<F1R (F1A0)> f1_; }; // More specializations to overload also with F2, F3, etc. int main() { char sep = '\n'; void BOOST_LOCAL_FUNCTION_PARAMS(const double& num, const bind& sep) { std::cout << num << sep; } BOOST_LOCAL_FUNCTION_NAME(print_d) void BOOST_LOCAL_FUNCTION_PARAMS(const std::string& num, const bind& sep) { std::cout << num << sep; } BOOST_LOCAL_FUNCTION_NAME(print_s) overload<void (const double&), void (const std::string&)> print( print_d, print_s); std::vector<double> d(2); d[0] = 1.2; d[1] = 3.4; std::for_each(d.begin(), d.end(), print); std::vector<std::string> s(3); s[0] = "ab"; s[1] = "cd"; s[2] = "ef"; std::for_each(s.begin(), s.end(), print); return 0; } -- Lorenzo

On 08/05/2011 16:04, Lorenzo Caminiti wrote:
auto /* or the real type */ l = overload(l1, l2);
Does Boost already have a functor overloader like overload() above?
I do not think so.
template<typename F0, typename F1, typename F2 = void, typename F3 = void> struct overload { };
template<typename F0R, typename F0A0, typename F1R, typename F1A0> struct overload<F0R (F0A0), F1R (F1A0)> { overload(boost::function<F0R (F0A0)> f0, boost::function<F1R (F1A0)> f1): f0_(f0), f1_(f1) {} F0R operator()(F0A0 a0) const { return f0_(a0); } F1R operator()(F1A0 a0) const { return f1_(a0); } private: boost::function<F0R (F0A0)> f0_; boost::function<F1R (F1A0)> f1_; };
// More specializations to overload also with F2, F3, etc.
The type erasure appear unnecessary, and this implementation has big forwarding problems. What about template<typename F0, typename F1> struct overload_t : F0, F1 { overload_t(F0 const& f0, F1 const& f1) : F0(f0), F1(f1) { } using F0::operator(); using F1::operator(); }; template<typename F0, typename F1> overload_t<F0, F1> overload(F0 const& f0, F1 const& f1) { return overload_t<F0, F1>(f0, f1); } Function pointers will have to be dealt with specially, though.

On Sun, May 8, 2011 at 11:22 AM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 08/05/2011 16:04, Lorenzo Caminiti wrote:
auto /* or the real type */ l = overload(l1, l2);
Does Boost already have a functor overloader like overload() above?
I do not think so.
template<typename F0, typename F1, typename F2 = void, typename F3 = void> struct overload { };
template<typename F0R, typename F0A0, typename F1R, typename F1A0> struct overload<F0R (F0A0), F1R (F1A0)> { overload(boost::function<F0R (F0A0)> f0, boost::function<F1R (F1A0)> f1): f0_(f0), f1_(f1) {} F0R operator()(F0A0 a0) const { return f0_(a0); } F1R operator()(F1A0 a0) const { return f1_(a0); } private: boost::function<F0R (F0A0)> f0_; boost::function<F1R (F1A0)> f1_; };
// More specializations to overload also with F2, F3, etc.
The type erasure appear unnecessary, and this implementation has big forwarding problems.
What about
template<typename F0, typename F1> struct overload_t : F0, F1 { overload_t(F0 const& f0, F1 const& f1) : F0(f0), F1(f1) { }
using F0::operator(); using F1::operator(); };
template<typename F0, typename F1> overload_t<F0, F1> overload(F0 const& f0, F1 const& f1) { return overload_t<F0, F1>(f0, f1); }
Yes, makes sense. Using your suggestion: #include <boost/local/function.hpp> #include <boost/function.hpp> #include <vector> #include <algorithm> #include <iostream> #include <string> namespace boost { namespace local { namespace function { template<typename F0, typename F1, typename F2 = void, typename F3 = void> struct overloaded {}; // Specialization for 2 functions. template<typename F0, typename F1> struct overloaded<F0, F1>: F0, F1 { overloaded(F0 const& f0, F1 const& f1): F0(f0), F1(f1) {} using F0::operator(); using F1::operator(); }; template<typename F0, typename F1> overloaded< boost::function<F0>, boost::function<F1> > overload( boost::local::aux::function<F0> const& f0 , boost::local::aux::function<F1> const& f1 ) { return overloaded< boost::function<F0>, boost::function<F1> >(f0, f1); } // Specialization for 3 functions. template<typename F0, typename F1, typename F2> struct overloaded<F0, F1, F2>: F0, F1, F2 { overloaded(F0 const& f0, F1 const& f1, F2 const& f2): F0(f0), F1(f1), F2(f2) {} using F0::operator(); using F1::operator(); using F2::operator(); }; template<typename F0, typename F1, typename F2> overloaded< boost::function<F0>, boost::function<F1>, boost::function<F2> > overload( boost::local::aux::function<F0> const& f0 , boost::local::aux::function<F1> const& f1 , boost::local::aux::function<F2> const& f2 ) { return overloaded< boost::function<F0>, boost::function<F1>, boost::function<F2> >(f0, f1, f2); } // More specializations for more functions... }}} // namespace boost::local::function // More specializations to overload also with F2, F3, etc. int main() { char sep = '\n'; void BOOST_LOCAL_FUNCTION_PARAMS(const double& item, const bind& sep) { std::cout << item << sep; } BOOST_LOCAL_FUNCTION_NAME(print_double) void BOOST_LOCAL_FUNCTION_PARAMS(const std::string& item, const bind& sep) { std::cout << item << sep; } BOOST_LOCAL_FUNCTION_NAME(print_string) void BOOST_LOCAL_FUNCTION_PARAMS(const char& item, const bind& sep) { std::cout << item << sep; } BOOST_LOCAL_FUNCTION_NAME(print_char) boost::local::function::overloaded< boost::function< void (const double&) > , boost::function< void (const std::string&) > , boost::function< void (const char&) > > print = boost::local::function::overload( print_double, print_string, print_char); std::vector<double> d(2); d[0] = 1.2; d[1] = 3.4; std::for_each(d.begin(), d.end(), print); std::vector<std::string> s(3); s[0] = "ab"; s[1] = "cd"; s[2] = "ef"; std::for_each(s.begin(), s.end(), print); char c[4] = {'x', 'y', 'z', 'w'}; std::for_each(c, c + 4, print); return 0; }
Function pointers will have to be dealt with specially, though.
This is not an issue for Boost.Local. If overload() and overloaded<> where to be added to Boost.Function instead, this case should be handled. I will make a note of this in Boost.Local docs rationale. Thanks a lot. On a separate note, Boost.Local does not allow to name a local function after an operator. Would that ever be useful? -- Lorenzo

On Sun, May 8, 2011 at 1:06 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Sun, May 8, 2011 at 11:22 AM, Mathias Gaunard
The type erasure appear unnecessary, and this implementation has big forwarding problems.
What about
Yes, makes sense. Using your suggestion:
Hi all, the following code compiles and runs just fine on GCC but it given the error below on MSVC. The error seems to be about a conversion to boost::function_base inside Boost.Function... #include <boost/local/function.hpp> #include <boost/function.hpp> #include <vector> #include <algorithm> #include <iostream> #include <string> namespace boost { namespace local { namespace function { template<typename F0, typename F1, typename F2 = void, typename F3 = void> struct overload {}; // Specialization for 2 functions. template<typename F0, typename F1> struct overload<F0, F1>: F0, F1 { overload(F0 const& f0, F1 const& f1): F0(f0), F1(f1) {} using F0::operator(); using F1::operator(); }; }}} // namespace boost::local::function // More specializations to overload also with F2, F3, etc. int main() { char sep = '\n'; void BOOST_LOCAL_FUNCTION_PARAMS(const double& item, const bind& sep) { std::cout << item << sep; } BOOST_LOCAL_FUNCTION_NAME(print_double) void BOOST_LOCAL_FUNCTION_PARAMS(const std::string& item, const bind& sep) { std::cout << item << sep; } BOOST_LOCAL_FUNCTION_NAME(print_string) boost::function< void (const double&) > pd(print_double); boost::function< void (const std::string&) > ps(print_string); boost::local::function::overload< boost::function< void (const double&) > , boost::function< void (const std::string&) > > print(pd, ps); std::vector<double> d(2); d[0] = 1.2; d[1] = 3.4; std::for_each(d.begin(), d.end(), print); std::vector<std::string> s(3); s[0] = "ab"; s[1] = "cd"; s[2] = "ef"; std::for_each(s.begin(), s.end(), ps); return 0; } E:\sandbox\boost-sandbox-local\libs\local\example>bjam -q overload_va ...patience... ...found 714 targets... ...updating 3 targets... compile-c-c++ bin\msvc-8.0\debug\threading-multi\overload_va.obj overload_va.cpp e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(601) : error C2594: 'argument' : ambiguous conversions from 'boost::local::function::overloa d<F0,F1> *' to 'const boost::function_base *' with [ F0=boost::function<void (const double &)>, F1=boost::function<void (const std::string &)> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(492) : see reference to function template instantiation 'bool boost::detail::functio n::basic_vtable1<R,T0>::assign_to<F>(FunctionObj,boost::detail::function::functi on_buffer &,boost::detail::function::function_obj_tag)' being compiled with [ R=void, T0=const double &, F=boost::local::function::overload<boost::function<void (const doubl e &)>,boost::function<void (const std::string &)>>, FunctionObj=boost::local::function::overload<boost::function<void (c onst double &)>,boost::function<void (const std::string &)>> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(909) : see reference to function template instantiation 'bool boost::detail::functio n::basic_vtable1<R,T0>::assign_to<Functor>(F,boost::detail::function::function_b uffer &)' being compiled with [ R=void, T0=const double &, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>>, F=boost::local::function::overload<boost::function<void (const doubl e &)>,boost::function<void (const std::string &)>> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(722) : see reference to function template instantiation 'void boost::function1<R,T0> ::assign_to<Functor>(Functor)' being compiled with [ R=void, T0=const double &, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(1043 ) : see reference to function template instantiation 'boost::function1<R,T0>::fu nction1<Functor>(Functor,int)' being compiled with [ R=void, T0=const double &, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>> ] overload_va.cpp(57) : see reference to function template instantiation ' boost::function<Signature>::function<boost::local::function::overload<F0,F1>>(Fu nctor,int)' being compiled with [ Signature=void (const double &), F0=boost::function<void (const double &)>, F1=boost::function<void (const std::string &)>, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(601) : error C2594: 'argument' : ambiguous conversions from 'boost::local::function::overloa d<F0,F1> *' to 'const boost::function_base *' with [ F0=boost::function<void (const double &)>, F1=boost::function<void (const std::string &)> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(492) : see reference to function template instantiation 'bool boost::detail::functio n::basic_vtable1<R,T0>::assign_to<F>(FunctionObj,boost::detail::function::functi on_buffer &,boost::detail::function::function_obj_tag)' being compiled with [ R=void, T0=const std::basic_string<char,std::char_traits<char>,std::allocato r<char>> &, F=boost::local::function::overload<boost::function<void (const doubl e &)>,boost::function<void (const std::string &)>>, FunctionObj=boost::local::function::overload<boost::function<void (c onst double &)>,boost::function<void (const std::string &)>> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(909) : see reference to function template instantiation 'bool boost::detail::functio n::basic_vtable1<R,T0>::assign_to<Functor>(F,boost::detail::function::function_b uffer &)' being compiled with [ R=void, T0=const std::basic_string<char,std::char_traits<char>,std::allocato r<char>> &, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>>, F=boost::local::function::overload<boost::function<void (const doubl e &)>,boost::function<void (const std::string &)>> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(722) : see reference to function template instantiation 'void boost::function1<R,T0> ::assign_to<Functor>(Functor)' being compiled with [ R=void, T0=const std::basic_string<char,std::char_traits<char>,std::allocato r<char>> &, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>> ] e:\sandbox\boost-trunk.windows\boost/function/function_template.hpp(1043 ) : see reference to function template instantiation 'boost::function1<R,T0>::fu nction1<Functor>(Functor,int)' being compiled with [ R=void, T0=const std::basic_string<char,std::char_traits<char>,std::allocato r<char>> &, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>> ] overload_va.cpp(57) : see reference to function template instantiation ' boost::function<Signature>::function<boost::local::function::overload<F0,F1>>(Fu nctor,int)' being compiled with [ Signature=void (const std::string &), F0=boost::function<void (const double &)>, F1=boost::function<void (const std::string &)>, Functor=boost::local::function::overload<boost::function<void (const double &)>,boost::function<void (const std::string &)>> ] call "C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat" x86 >nul cl /Zm800 -nologo @"bin\msvc-8.0\debug\threading-multi\overload_va.obj.rsp" ...failed compile-c-c++ bin\msvc-8.0\debug\threading-multi\overload_va.obj... ...failed updating 1 target... Thanks a lot! -- Lorenzo

lcaminiti wrote:
On Sun, May 8, 2011 at 1:06 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Sun, May 8, 2011 at 11:22 AM, Mathias Gaunard
The type erasure appear unnecessary, and this implementation has big forwarding problems.
What about
Yes, makes sense. Using your suggestion:
Hi all, the following code compiles and runs just fine on GCC but it given the error below on MSVC. The error seems to be about a conversion to boost::function_base inside Boost.Function...
[...]
I have implemented local function overloading: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local... http://svn.boost.org/svn/boost/sandbox/local/boost/local/function/overload.h... http://svn.boost.org/svn/boost/sandbox/local/boost/local/aux_/overload_base.... #include <boost/local/function/overload.hpp> // Include header for overloading. #include <boost/local/function.hpp> #include <vector> #include <algorithm> #include <iostream> #include <string> int print_add(int x, int y) { std::cout << x << " + " << y << " = "; return x + y; } int main() { char end = '\n'; void BOOST_LOCAL_FUNCTION_PARAMS(const std::string& item, const bind& end) { std::cout << item << " (string)" << end; } BOOST_LOCAL_FUNCTION_NAME(print_string) void BOOST_LOCAL_FUNCTION_PARAMS(const double& item, const char* name, default " (double)", const bind& end) { std::cout << item << name << end; } BOOST_LOCAL_FUNCTION_NAME(print_double) boost::local::function::overload< void (const std::string&) , void (const double&) // Overload 1st param type. , void (const double&, const char*) // Overload giving default param. , int (int, int) // Overload giving 2 params (from function pointer). > print(print_string, print_double, print_double, print_add); std::vector<std::string> s(3); s[0] = "ab"; s[1] = "cd"; s[2] = "ef"; std::for_each(s.begin(), s.end(), print); // Call `print_string` 1-param. std::vector<double> d(2); d[0] = 1.2; d[1] = 3.4; std::for_each(d.begin(), d.end(), print); // Call `print_double` 1-param. print(-1.234, " (real)"); // Call `print_double` 2-params. std::cout << print(2, 3) << std::endl; // Call `print_add`. return 0; } --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-t... Sent from the Boost - Dev mailing list archive at Nabble.com.
participants (14)
-
Gordon Woodhull
-
Jeffrey Lee Hellrung, Jr.
-
Jeremy Maitin-Shepard
-
Joel de Guzman
-
John Bytheway
-
lcaminiti
-
Lorenzo Caminiti
-
Mathias Gaunard
-
Michael Caisse
-
Steven Watanabe
-
Thomas Heller
-
Thomas Klimpel
-
Vicente BOTET
-
Yechezkel Mett