Click here to Skip to main content
12,999,157 members (44,580 online)
Click here to Skip to main content
Add your own
alternative version


17 bookmarked
Posted 3 Nov 2005

Win32 File Name Iteration Boost Way

, 3 Nov 2005
Rate this:
Please Sign up or sign in to vote.
A Port of ::FindFirstFile to Boost.Range and Boost.Foreach


I was inspired by the excellent article, Win32 File Name Iteration STL Way. I think the problem of the article is that the handle of ::FindFirstFile is managed by iterators. After combating Boost.Range for months, I realized that Boost.Range could remove that complexity. The result was named find_file_range, which is the direct translation from ::FindFirstFile to C++.



find_file_range is a model of Single Pass Range whose value_type is WIN32_FIND_DATA. If you are not familiar with Boost.Range concepts, you could regard it as something like a Container which provides Input Iterators:

find_file_range ffrng("*.*");
typedef boost::range_result_iterator<find_file_range>::type iter_t;
for (iter_t it = boost::begin(ffrng), last = boost::end(ffrng); it != last; ++it) {
  std::cout << it->cFileName << std::endl;

If you iterate find_file_range twice, the behavior is undefined. This code proves find_file_range is a thin wrapper of ::FindFirstFile, but seems somewhat clumsy. Why must we write the idiom hundreds of times? If you resent it, it will come.

Foreach will Come

Boost.Foreach (accepted into Boost, but not yet part of the release) provides foreach that is missing from C++:

find_file_range ffrng("*.*");
BOOST_FOREACH (WIN32_FIND_DATA& data, ffrng) {
  std::cout << data.cFileName << std::endl;

Is this a new language? No, It's C++. The implementation is magical. If you are interested in it, check Conditional Love: FOREACH Redux written by Eric Niebler.


One class, one responsibility. find_file_range doesn't offer any filtering using dwFileAttributes of WIN32_FIND_DATA. Instead, Adaptable Predicates named find_file_is_xxx are provided. They are available for boost::make_filter_range, which is a part of Boost.RangeEx:

find_file_range ffrng("*.*");
  WIN32_FIND_DATA& data,
  boost::make_filter_range(ffrng, boost::not1(find_file_is_dots()))
  std::cout << data.cFileName << std::endl;

std::not1 is completely broken by reference-to-reference problem, so you must use boost::not1 from Boost.Functional.


As a mark of respect for the original article, find_file_construct template that makes a model of Adaptable Unary Functor is provided for those who want to get cFileName of WIN32_FIND_DATA as a string object. It is available for boost::make_transform_range:

find_file_range ffrng("*.*");
  std::string const& filename,
  boost::make_transform_range(ffrng, find_file_construct<std::string>())
  std::cout << filename << std::endl;

find_file_construct template takes a type Sequence. If your string type is not a Sequence like CString, you could use find_file_stringize instead.

Chain of Range Adaptors

The chain of filtering and transforming is also available:

find_file_range ffrng("*.*");
  std::string const& filename,
  std::cout << filename << std::endl;

This chain is lazy and functional, but unreadable. And so Boost.RangeEx provides Range Adaptors:

find_file_range ffrng("*.*");
  std::string const& filename,
  ffrng |
    boost::adaptor::filter(boost::not1(find_file_is_hidden())) |
    boost::adaptor::filter(boost::not1(find_file_is_directory())) |
  std::cout << filename << std::endl;

This is rather "procedural" and shows the future of C++.

Points of Interest

find_file_range is just like a disposable container and doesn't offer any additional functionalities unlike Boost.Filesystem, but it doesn't demand any additional resources. Boost.Range concepts are wide-open to such classes. In fact, find_file_range depends on the fact that clients don't iterate twice, while boost::iterator_range depends on the fact that holding iterators are valid. You could easily make many classes conform to the concepts. I hope this article helps:

std::string inputs; {
  boost::copy(make_istream_range<char>(std::cin), std::back_inserter(inputs));
std::cout << inputs << std::endl;


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Japan Japan
I am worried about my poor English...

You may also be interested in...


Comments and Discussions

Generalassert Pin
eugeneugene8-Nov-05 3:56
membereugeneugene8-Nov-05 3:56 
GeneralRe: assert Pin
mb2sync8-Nov-05 11:50
membermb2sync8-Nov-05 11:50 

Yes, I was wrong.D'Oh! | :doh:
I updated the demo a few days ago.
find_file_range no longer invokes assertion in the case of INVALID_HANDLE_VALUE.
Instead, find_file_range becomes an empty range.
(Win32 document doesn't list the value of GetLastError() in the case of
INVALID_HANDLE_VALUE, I think that's the answer.)

Generalboost::dir_it Pin
Todd Smith4-Nov-05 9:25
memberTodd Smith4-Nov-05 9:25 
GeneralRe: boost::dir_it Pin
mb2sync4-Nov-05 12:56
membermb2sync4-Nov-05 12:56 
GeneralRe: boost::dir_it Pin
Gast1281-Oct-12 3:37
memberGast1281-Oct-12 3:37 
Generalgood exploration of boost concepts Pin
Martin.Holzherr4-Nov-05 2:22
memberMartin.Holzherr4-Nov-05 2:22 
GeneralRe: good exploration of boost concepts Pin
mb2sync4-Nov-05 4:53
membermb2sync4-Nov-05 4:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170622.1 | Last Updated 4 Nov 2005
Article Copyright 2005 by mb2sync
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid