Is this a safe workaround? I want to use vector bool but need to pass a pointer to old code expecting C-style array.
typedef std::basic_string<bool> vector_bool;
int main()
{
vector_bool ab;
ab.push_back(true);
ab.push_back(true);
ab.push_back(true);
ab.push_back(false);
bool *b = &ab[0];
b[1] = false;
}
Edit: Thanks for suggestions of other solutions, but I would really like a definite answer on my above solution. Thanks.
I'm not sure about std::basic_string<bool>
because that will instantiate std::char_traits<bool>
and I'm not sure if the standard requires that to be defined, or if the char_traits
primary template can be left undefined, with only explicit specializations such as char_traits<char>
being defined. You're not allowed to provide your own specialization of char_traits<bool>
because you can only specialize standard templates if the specialization depends on a user-defined type, which bool
obviously isn't. That said, it might work if your stdlib does have a default char_traits
definition, and you don't try to use an string operations that require members of char_traits
to do anything useful.
Alternatively, this is hacky but might work:
struct boolish { bool value; };
inline boolish make_boolish(bool b) { boolish bish = { b }; return bish; }
std::vector<boolish> b;
b.push_back( make_boolish(true) );
bool* ptr = &b.front().value;
boolish
is a trivial type, so as long as an array of boolish
has the same representation as an array of bool
(which you'd need to check for your compiler, I used a static_assert
to check there is no padding) then you might get away with it, although it probably violates the aliasing rules because *ptr
and *++ptr
are not part of the same array, so incrementing the pointer doesn't point to the next boolish::value
it points "past the end" of the previous one (even if those two locations actually have the same address, although [basic.compound]/3 does seem to say that ++ptr
does "point to" the next bool
).
The syntax gets a bit easier with C++11, you don't need make_boolish
...
#include <vector>
#include <assert.h>
struct boolish { bool value; };
int main()
{
std::vector<boolish> vec(10);
vec.push_back( boolish{true} );
bool* ptr = &vec.front().value;
assert( ptr[10] == true );
ptr[3] = true;
assert( vec[3].value == true );
static_assert( sizeof(boolish) == sizeof(bool), "" );
boolish test[10];
static_assert( sizeof(test) == (sizeof(bool)*10), "" );
}
From "Working Draft C++, 2012-11-02"
21.1 General [strings.general]
1 This Clause describes components for manipulating sequences of any non-array POD (3.9) type.21.4.1 basic_string general requirements [string.require]
5 The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0 <= n < s.size().
but
6 References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object:
— as an argument to any standard library function taking a reference to non-const basic_string as an argument.233
— Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and rend.
So, you should be safe as long as you pay attention, not to call these functions, while you use the raw array somewhere else.
Update:
Character traits and requirements are described in 21.2 Character traits [char.traits] and 21.2.1 Character traits requirements [char.traits.require]. Additionally, typedefs and specializations are described in 21.2.2 traits typedefs [char.traits.typedefs] and 21.2.3 char_traits specializations [char.traits.specializations] respectively.
These traits are used in the Input/output library as well. So there are requirements, like eof()
or pos_type
and off_type
, which don't make sense in the context of basic_string
.
I don't see any requirement for these traits to be actually defined by an implementatin, besides the four specializations for char
, char16_t
, char32_t
and wchar_t
.
Although, it worked out of the box with gcc 4.7 with your example, I defined a minimal bool_traits
with just
struct bool_traits {
typedef bool char_type;
static void assign(char_type &r, char_type d);
static char_type *copy(char_type *s, const char_type *p, std::size_t n);
static char_type *move(char_type *s, const char_type *p, std::size_t n);
};
took the default implementation provided (gcc 4.7), and used that like
std::basic_string<bool, bool_traits> ab;
Your environment might already provide a working implementation. If not, you can implement a simple bool_traits
or a template specialization std::char_traits<bool>
yourself.
You can see the complete interface for character traits in the Working Draft, PDF or at cppreference.com - std::char_traits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With