1

While working on some old code it encountered an std::unique_ptr<bool> used for storing some bool-values (allocated in class constructor and used as an array).

When I tried to replace it with a std::vector<bool> I encountered a problem when I had to call a library function which takes a count and a pointer to the first boolean value (const bool*): There is a template specialization for std::vector<bool> which compresses 8 boolean values into one byte and therefore it is not possible to get a bool* pointer to the data without decompressing it first.

I have already found some solutions by Google search or the StackOverflow article C++11 vector<bool> performance issue (with code example) but none of them are working for me (i.e. using a struct which contains a boolean would work, but it makes the code I try to simplify more complex; std::valarray does not provide a data() member)

There is also an article "How to prevent specialization of std::vector<bool>" but all solutions there are just workarounds and I am not convinced of the phrase "bool and unsigned char typically take the same amount of memory on their own" (mentioned at compiler error when pointing to an element of std::vector<bool>?)

I also checked Alternative to vector<bool> but we do not use boost in our solution and I am not willing to add this dependency for a single use.

My Question is: Is there a way to ignore a template spezialization and explicitly use the unspezialized template for a type?

For example

#include <iostream>

template<class T>
class MyTemplate
{
public:
  static const int Value = 0;
}

template<>
class MyTemplate<double>
{
public: 
  static const int Value = 1;
};

int main(int argc, char **argv)
{
  // How can I make MyTemplate<double> ignore the spezialization and output 0?
  std::cout << "0==" << MyTemplate<double>::Value << std::endl;

  return 0;
}
Community
  • 1
  • 1
Andreas H.
  • 1,584
  • 9
  • 21
  • How about wrapping the book in some struct and continue from there? – user3104201 May 27 '16 at 07:39
  • Thats the "standard" solution, but for that to work with the library call I need a reinterpret_cast and when read or writing to an item I need to access the value member of the struct or I have to implement auto-boxing/unboxing in the struct which makes it way to complicated. – Andreas H. May 27 '16 at 07:43
  • 5
    There are many ways to have an array of boolean values but bypassing the `vector` specialisation is not one of them. – n. 'pronouns' m. May 27 '16 at 07:52
  • 1
    The equivalent to `std::unique_ptr` would be `unique`. `std::vector` would be for `std::unique_ptr`... – Jarod42 May 27 '16 at 07:54
  • Yes, thats one reason why I want to change this code. (are you sure you intended to write `unique` and not simply `bool`?) – Andreas H. May 27 '16 at 08:04
  • Another solution might be to use `deque` or any other container – M.M May 27 '16 at 11:14
  • Do you really need `data()`? `&container[x]` will provide the pointer to the individual element you want for both `std::deque` and `std::valarray`. For `std::valarray`, `&container[0]` will give the same thing as `data()`, if you **really** need to do pointer arithmetic. Lastly, doing your own container for this data type is not too complicated. – coyotte508 May 27 '16 at 11:19

3 Answers3

3

The answer is NO, because there is no guarantee an unspecialized template even exists.

In particular, it's quite reasonable for a compiler to have a specializations for all built-in types. So you typically see a compile-time dispatch: vector<T> forwards to __VectorImplBuiltIn<T> whenever T is a built-in type, and __VectorImplBuiltIn<T> in turn is specialized for each individual case. So vector<float> may use AVX to copy 4 floats at a time, and vector<bool> is packed.

Now there is no portable way to name that specific implementation class (it's literally an implementation detail) and that unspecialized __VectorImplBuiltIn<T> wouldn't even have a generic implementation because the compiler vendor would obviously know all built-in types.

In this scheme, the "normal" vector<T> would expand to __VectorImplClassType<T>, and that could be unusuable for T==bool because bool doesn't have a constructor.

So a perfectly reasonable scheme where std::vector<T> starts out by distinguishing types with and without constructor will make your idea impossible. And therefore it's no surprise that the ISO C++ Standard doesn't allow what you want.

MSalters
  • 159,923
  • 8
  • 140
  • 320
2

You can create a wrapper struct that appears to behave identically to a bool, thus not requiring modification of code expecting it to be a bool:

struct B {
    bool val;
    B() {}
    B(bool val): val(val) {}
    operator bool&() { return val; }
    operator const bool&() const { return val; }
    bool* operator&() { return &val; }
    const bool* operator&() const { return &val; }
};

Then all of the following are possible:

B a = true, b(0);
a || 2 == 1;
5 ^ a;
const bool& x = a;
bool* y = &a;
a &= b;
!a;
feersum
  • 627
  • 4
  • 11
  • That's the solution from http://stackoverflow.com/questions/36932684/c11-vectorbool-performance-issue-with-code-example I wrote about in my question. But it adds a lot of complexity to the code and it still requires a reinterpret_cast for the library call. – Andreas H. May 27 '16 at 08:15
  • 1
    @AndreasH. I don't see anything like this in that link. How does it require a reinterpret_cast? – feersum May 27 '16 at 08:17
  • When calling the library function which requires a `bool *` as you can see at https://ideone.com/exMf6X – Andreas H. May 27 '16 at 08:28
  • 1
    @AndreasH. You could replace that part with `libraryFunction(&v[0])`, assuming that it is not also in the library. – feersum May 27 '16 at 08:33
  • 1
    That would work but - I am sorry - this is not an answer to my question _'Is there a way to ignore a template spezialization and explicitly use the unspezialized template for a type?'_ – Andreas H. May 27 '16 at 08:53
  • @AndreasH. In that case, the answer is "No." – feersum May 27 '16 at 09:11
2

This isn't an answer to your question exactly, although it may be an answer to your problems.

You said that you're trying to use a library that takes bool * as a parameter and that you are not using std::valarray because it doesn't have data().

But doesn't the following work?

#include <iostream>
#include <valarray>

using namespace std;

void doStuff(bool *x) {
    *x = true;
}

int main() {
    valarray<bool> v = {false,false,false,false,false,false};

    doStuff(&v[2]);

    for (bool b : v) {
        cout << b << endl;
    }

    //if you *really* want data(), &v[0] does the same
    return 0;
}

Live Demo

Note that valarray is guaranteed to have contiguous memory.


An alternative is to create a replacement container, an example named SimpleVector is given here which only necessits a simple header file to be added, and the poster of the code references a book from Mark Allen Weiss.

In that implementation begin() behaves the same as data().

Although the code is pre-c++11, so it doesn't implement a constructor for &&.

Community
  • 1
  • 1
coyotte508
  • 6,974
  • 5
  • 34
  • 58
  • The library function takes a count and a pointer to the first bool. &v[0] would work as long as `valarray` stores its data as boolean values in a continuous block, but this behaviour is implementation dependent. – Andreas H. May 27 '16 at 12:42
  • 1
    @AndreasH. actually it is guaranteed to work, I edited my post with a [reference](http://stackoverflow.com/questions/11143109/does-valarray-have-contiguous-memory-alignment). – coyotte508 May 27 '16 at 13:00
  • Thank you for the reference. This **is** a solution to my problem but I am afraid its not an acceptable answer to my question. I am sorry but I'll have to accept MSalters answer because its matches the question but at least I can give you an upvote. – Andreas H. May 27 '16 at 14:35