[Lambda] Help with if_then_else

Consider this (working) code using Boost.FileSystem: fs::directory_iterator di(dir); fs::directory_iterator end; while (di != end) { if (is_directory(*di)) cout << "D\n"; else cout << "~D\n"; ++di; } This looks like it should be lambda-able. Here's my attempt: for_each(fs::directory_iterator(dir), fs::directory_iterator(), if_then_else(bind(&fs::is_directory, _1), cout << "D\n", cout << "~D\n")); VC7.1 doesn't like this -- the diagnostics are below. Any idea how I can make this work? Thanks, Scott fs.cpp(39) : error C2784: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::ifthenelse_action,boost::tuples: :tuple<boost::lambda::lambda_functor<Arg1>,boost::lambda::lambda_functor<Arg2>,boost::lambda::lambda_functor<Arg3>>>> boost::lambda::if_then_else (const boost::lambda::lambda_functor<Arg1> &,const boost::lambda::lambda_functor<Arg2> &,const boost::lambda::lambda_functor<Arg3> &)' : could no t deduce template argument for 'const boost::lambda::lambda_functor<T2> &' from 'std::basic_ostream<_Elem,_Traits>' with [ _Elem=char, _Traits=std::char_traits<char> ] D:\C++\Boost\Current\boost\lambda\if.hpp(100) : see declaration of 'boost::lambda::if_then_else' fs.cpp(39) : error C2784: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::ifthenelse_action,boost::tuples: :tuple<boost::lambda::lambda_functor<Arg1>,boost::lambda::lambda_functor<Arg2>,boost::lambda::lambda_functor<Arg3>>>> boost::lambda::if_then_else (const boost::lambda::lambda_functor<Arg1> &,const boost::lambda::lambda_functor<Arg2> &,const boost::lambda::lambda_functor<Arg3> &)' : could no t deduce template argument for 'const boost::lambda::lambda_functor<T2> &' from 'std::basic_ostream<_Elem,_Traits>' with [ _Elem=char, _Traits=std::char_traits<char> ] D:\C++\Boost\Current\boost\lambda\if.hpp(100) : see declaration of 'boost::lambda::if_then_else' fs.cpp(39) : error C2784: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::ifthenelse_action,boost::tuples: :tuple<boost::lambda::lambda_functor<Arg1>,boost::lambda::lambda_functor<Arg2>,boost::lambda::lambda_functor<Arg3>>>> boost::lambda::if_then_else (const boost::lambda::lambda_functor<Arg1> &,const boost::lambda::lambda_functor<Arg2> &,const boost::lambda::lambda_functor<Arg3> &)' : could no t deduce template argument for 'const boost::lambda::lambda_functor<T2> &' from 'std::basic_ostream<_Elem,_Traits>' with [ _Elem=char, _Traits=std::char_traits<char> ] D:\C++\Boost\Current\boost\lambda\if.hpp(100) : see declaration of 'boost::lambda::if_then_else' fs.cpp(39) : error C2784: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::ifthenelse_action,boost::tuples: :tuple<boost::lambda::lambda_functor<Arg1>,boost::lambda::lambda_functor<Arg2>,boost::lambda::lambda_functor<Arg3>>>> boost::lambda::if_then_else (const boost::lambda::lambda_functor<Arg1> &,const boost::lambda::lambda_functor<Arg2> &,const boost::lambda::lambda_functor<Arg3> &)' : could no t deduce template argument for 'const boost::lambda::lambda_functor<T2> &' from 'std::basic_ostream<_Elem,_Traits>' with [ _Elem=char, _Traits=std::char_traits<char> ] D:\C++\Boost\Current\boost\lambda\if.hpp(100) : see declaration of 'boost::lambda::if_then_else'

On Mar 8, 2006, at 3:21 PM, Scott Meyers wrote:
Consider this (working) code using Boost.FileSystem:
fs::directory_iterator di(dir); fs::directory_iterator end; while (di != end) { if (is_directory(*di)) cout << "D\n"; else cout << "~D\n"; ++di; }
This looks like it should be lambda-able. Here's my attempt:
for_each(fs::directory_iterator(dir), fs::directory_iterator(), if_then_else(bind(&fs::is_directory, _1), cout << "D\n", cout << "~D\n"));
VC7.1 doesn't like this -- the diagnostics are below. Any idea how I can make this work?
I can spot one thing at least: Arguments to if_then_else must be lambda functions:
if_then_else(bind(&fs::is_directory, _1), var(cout) << "D\n", var(cout) << "~D\n"));
This delays the evaluation of the branches (which would otherwise just print D or ~D once, when the lambda function is created, rather than during every iteration of for_each Best, Jaakko

On 3/8/06, Scott Meyers <usenet@aristeia.com> wrote:
This looks like it should be lambda-able. Here's my attempt:
for_each(fs::directory_iterator(dir), fs::directory_iterator(), if_then_else(bind(&fs::is_directory, _1), cout << "D\n", cout << "~D\n"));
VC7.1 doesn't like this -- the diagnostics are below. Any idea how I can make this work?
Try out: for_each(fs::directory_iterator(dir), fs::directory_iterator(), if_then_else(bind(&fs::is_directory, _1), cout << constant("D\n"), cout << constant("~D\n"))); The problem is that 'cout << "D\n"' is getting called immediately - as it's not a lambda expression, by making "D\n" a delayed constant it becomes one. This is documented at http://tinyurl.com/7jq3v. Hope that helps, Daniel

Scott Meyers wrote:
Consider this (working) code using Boost.FileSystem:
fs::directory_iterator di(dir); fs::directory_iterator end; while (di != end) { if (is_directory(*di)) cout << "D\n"; else cout << "~D\n"; ++di; }
This looks like it should be lambda-able. Here's my attempt:
for_each(fs::directory_iterator(dir), fs::directory_iterator(), if_then_else(bind(&fs::is_directory, _1), cout << "D\n", cout << "~D\n"));
VC7.1 doesn't like this -- the diagnostics are below. Any idea how I can make this work?
The cout << "D\n" subexpression is evaluated immediately since it doesn't have any lambda components. Use var(cout) << "D\n" instead, or the ?: variant: cout << if_then_else_return( bind(&fs::is_directory, _1), "D\n", "~D\n" ) You could also make an alias for var(std::cout): var_type<std::ostream>::type cout = var( std::cout ); and use that in the lambda expressions.

I tried both suggested solutions (applying var to cout, applying constant to the output string -- see below), but neither works. What follows is a complete compilation unit (not program -- there's no main) that fails with both VC7.1 and gcc 3.4.2 when I uncomment either of the two for_each loops. The error messages are, um, not as enlightening as they might be. Any suggestions how to get this to work? Thanks, Scott #include <iostream> #include <string> #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/lambda/bind.hpp" #include "boost/lambda/if.hpp" void f(const std::string& dirName) { using namespace std; namespace fs = boost::filesystem; fs::path dir(dirName, fs::native); using namespace boost::lambda; // for_each(fs::directory_iterator(dir), fs::directory_iterator(), // if_then_else(bind(&fs::is_directory, _1), // cout << constant("D\n"), // cout << constant("~D\n"))); // for_each(fs::directory_iterator(dir), fs::directory_iterator(), // if_then_else(bind(&fs::is_directory, _1), // var(cout) << "D\n", // var(cout) << "~D\n")); }

On 3/8/06, Scott Meyers <usenet@aristeia.com> wrote:
The error messages are, um, not as enlightening as they might be. Any suggestions how to get this to work?
Thanks,
Scott
#include <iostream> #include <string> #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/lambda/bind.hpp" #include "boost/lambda/if.hpp"
You also need to include "boost/lambda/lambda.hpp", to declare operator<<. Daniel
participants (4)
-
Daniel James
-
Jaakko Jarvi
-
Peter Dimov
-
Scott Meyers