[libc++] std::count with bool types

I am trying out a recent clang 3.1 release candidate on Linux with and
ToT libc++ and have run into the following compilation error. This
test builds successfully using libstdc++:

$ clang -v
clang version 3.1 (branches/release_31 155817)
Target: x86_64-unknown-linux-gnu
Thread model: posix
.
$ cat test_count.cxx
#include <iostream>
#include <algorithm>
#include <vector>

int main ()
{
    // counting boolean elements in array
    bool bool_array[] = { true,false,true,false,true,false,true,true};
    int mycount = (int) std::count (bool_array, bool_array+8, true);
    std::cout << "true appears " << mycount << " times.\n";

    // counting boolean elements in container
    std::vector<bool> bool_vector( bool_array,bool_array+8 );
    mycount = (int) std::count (bool_vector.begin(), bool_vector.end(), false);
    std::cout << "false appears " << mycount << " times.\n";
}

$ clang++ -stdlib=libc++ test_count.cxx -o testit
In file included from test_count.cxx:1:
In file included from /usr/include/c++/v1/iostream:40:
In file included from /usr/include/c++/v1/istream:156:
In file included from /usr/include/c++/v1/ostream:134:
In file included from /usr/include/c++/v1/bitset:120:
/usr/include/c++/v1/__bit_reference:236:27: error: '__storage_type' is
a private member of
      'std::__1::__bit_iterator<std::__1::vector<bool,
std::__1::allocator<bool> >, false, 0>'
    typedef typename _It::__storage_type __storage_type;
                          ^
/usr/include/c++/v1/__bit_reference:299:16: note: in instantiation of
function template specialization
      'std::__1::__count_bool_true<std::__1::vector<bool,
std::__1::allocator<bool> > >' requested here
        return __count_bool_true(__first, static_cast<typename
_Cp::size_type>(__last - __first));
               ^
test_count.cxx:14:21: note: in instantiation of function template
specialization 'std::__1::count<std::__1::vector<bool,
      std::__1::allocator<bool> >, bool>' requested here
    mycount = (int) std::count (bool_vector.begin(), bool_vector.end(), false);
                    ^
/usr/include/c++/v1/__bit_reference:1071:84: note: declared private here
    typedef typename _Cp::__storage_type
            __storage_type;

            ^
/usr/include/c++/v1/__bit_reference:238:50: error: '__bits_per_word'
is a private member of
      'std::__1::__bit_iterator<std::__1::vector<bool,
std::__1::allocator<bool> >, false, 0>'
    static const unsigned __bits_per_word = _It::__bits_per_word;
                                                 ^
/usr/include/c++/v1/__bit_reference:1074:27: note: declared private here
    static const unsigned __bits_per_word = _Cp::__bits_per_word;

etc etc

-Michael

Sorry about that! Somehow some friend statements were missing. Fix committed revision 156543.

Thanks for the report!

Howard

And it is still wrong. Sorry. Working on it...

Howard

Ok, fix committed revision 156546.

Sorry about the thrash. As an attempt to save what little face I have left, I've expanded your example and put some timers on it. On OS X, compiling with -O3 and in 64 bit mode:

#include <iostream>
#include <algorithm>
#include <chrono>
#include <random>
#include <vector>

int main ()
{
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::nanoseconds ns;
    std::mt19937_64 eng;
    std::uniform_int_distribution<bool> d;
    const unsigned N = 10000;
    // counting boolean elements in array
    bool bool_array[N];
    for (auto& b : bool_array)
        b = d(eng);
    auto t0 = Clock::now();
    int mycount = (int) std::count (bool_array, bool_array+N, true);
    auto t1 = Clock::now();
    std::cout << "true appears " << mycount << " times.\n";
    std::cout << "count took " << ns(t1-t0).count() << "ns\n";
    t0 = Clock::now();
    mycount = (int) std::count (bool_array, bool_array+N, false);
    t1 = Clock::now();
    std::cout << "false appears " << mycount << " times.\n";
    std::cout << "count took " << ns(t1-t0).count() << "ns\n";

    // counting boolean elements in container
    std::vector<bool> bool_vector( bool_array,bool_array+N );
    t0 = Clock::now();
    mycount = (int) std::count (bool_vector.begin(), bool_vector.end(), true);
    t1 = Clock::now();
    std::cout << "true appears " << mycount << " times.\n";
    std::cout << "count took " << ns(t1-t0).count() << "ns\n";
    t0 = Clock::now();
    mycount = (int) std::count (bool_vector.begin(), bool_vector.end(), false);
    t1 = Clock::now();
    std::cout << "false appears " << mycount << " times.\n";
    std::cout << "count took " << ns(t1-t0).count() << "ns\n";
}

I get:

true appears 5039 times.
count took 6922ns
false appears 4961 times.
count took 10328ns
true appears 5039 times.
count took 565ns
false appears 4961 times.
count took 537ns

So working with bits instead of bools is both correct and about 15 times faster (if you have enough bools anyway). This is what the private header <__bit_reference> is all about: specializing a few of the std::algorithms for bit iterators, used by both bitset and vector<bool>.

Howard

Thank you very much for the quick fix and the lesson! :slight_smile:

-Michael