Expected class-name before '{' token

I have made a class called LockableBitSet, that extends bitset in the standard library. But when I try to compile my project, I get the "expected class-name before '{' token" error in the header file. Here is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef LOCKABLEBITSET_HPP_
#define LOCKABLEBITSET_HPP_

#include <bitset>

namespace pub {
	class LockableBitSet:public std::bitset {
		private:
			bool locked = false;
		public:
			void lock();
			bool isUnlocked();
	};
}

#endif 


Now, I've done enough googling to know that this seems to be a matter of the compiler not knowing the type bitset when it gets to the class definition. But that's what I don't understand, since I include the bitset header first, so I would expect it to have read that entire file and thus the bitset class definition by that time.

Nevertheless, I tried out forward declaration like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef LOCKABLEBITSET_HPP_
#define LOCKABLEBITSET_HPP_

#include <bitset>

class std::bitset;

namespace pub {
	class LockableBitSet:public std::bitset {
		private:
			bool locked = false;
		public:
			void lock();
			bool isUnlocked();
	};
}

#endif 


Which just gives me the error "invalid use of template-name 'std::bitset' without an argument list. I have also read about a possible cause being circular references, but since I'm extending bitset, I can't see how that would be the case.

And while I doubt it's really a problem with the class itself, here it is, just for good measure:
1
2
3
4
5
6
7
8
9
10
11
#include "LockableBitSet.hpp"

namespace pub {
	void LockableBitSet::lock() {
		locked = true;
	}

	bool LockableBitSet::isUnlocked() {
		return !locked;
	}
}


So what am I doing wrong in the header file? While I'm new to C++, I have done a fair bit of tutorial reading and error searching, and I fail to see what the problem is in this case, or rather how to solve it.

Oh, and FYI I am using C++11, which is why I declare the locked variable like that.
Last edited on
1
2
3
4
5
6
7
#include <bitset>

template < std::size_t NBITS >
struct lockable_bitset : public std::bitset<NBITS> 
{
    // ...
};


std::bitset<> is not designed for inheritance; consider something like this instead:

1
2
3
4
5
6
7
template < std::size_t NBITS >
struct lockable_bitset : private std::bitset<NBITS> 
{
    using std::bitset<NBITS>::operator[] ;
    // etc.
    // ...
};


or

1
2
3
4
5
6
template < std::size_t NBITS >
struct lockable_bitset 
{
    // ...
    private: : std::bitset<NBITS> impl ;
};


Last edited on
Does that mean that I can't make a class that extends it, or merely that I shouldn't? The problem is that I need to write other classes that extend LockableBitset, that my project depends on using bitset, and that I need to be able to lock it down from being edited, thus the LockableBitSet class.
> Does that mean that I can't make a class that extends it, or merely that I shouldn't?

No, you can extend it.
Just that you should not publicly inherit from a std::bitset<> to extend it.


> and that I need to be able to lock it down from being edited, thus the LockableBitSet class.

The problem with public inheritance is this:

1
2
3
4
void foo( std::bitset<32>& bs )
{
     bs <<= 12U ; // perfectly valid on a bitset
}


1
2
3
4
void bar( lockable_bitset<32>& lbs )
{
       foo(lbs) ; // lbs is modified without a lock
}



If you are not already doing it, you should also provide a RAII wrapper a la std::lock_guard
http://en.cppreference.com/w/cpp/thread/lock_guard
Yes, this problem is exactly what I was planning to solve with this lock class, by also overriding some of the operators and setters in the bitset. But my reason for wanting a lock is not due to anything thread-related but to avoid the very problem you point out with bitsets, for one of my own classes. I.e. making sure that once it's locked, none of the data inside the class can be changed, which in this case means keeping the bitset as it is when lock() is called.

I can figure out that this is not best practice, but like I said I'm new to C++, so why is it a bad idea to publicly inherit bitset to extend it? After all, that IS what polymorphism is for, and I see no difference between extending my own class and a standard library class. So please enlighten me.
> making sure that once it's locked, none of the data inside the class can be changed,
> which in this case means keeping the bitset as it is when lock() is called.

If you inherit publicly from a std::bitset<>, there is an implicit conversion from lockable_bitset<N>& to std::bitset<N>&. Which defeats the very purpose of a lockable_bitset<>; std::bitset<> knows nothing about any lock.
See: http://www.objectmentor.com/resources/articles/lsp.pdf

Since a std::bitset<N> is inexpensive to copy, it may be simpler to just make a copy of the bitset when it is 'locked', use the copy, and restore the bitset from the copy when it is 'unlocked'.
I see what you mean, but that is exactly what I have planned to solve by overriding those operators that change the bitset, like sets and &= and so on, and in those I will simply just call my isUnlocked() function, and only if it returns true, will I call the same function from bitset. That way I ensure that whatever class extends LockableBitset can't be modified if it's been locked.

I will read through the linked article and think about what you have said as well. But returning to the original question, is there a fix for that error that lets me still have LockableBitset as a class, not a struct, AND extend bitset? I'm not saying I will end up using it, but I would never the less like to know how to fix that error.
> that is exactly what I have planned to solve by overriding those operators
> that change the bitset, like sets and &= and so on

You can't override functions that are not virtual.
Even if you hide the name of a non-virtual function in a derived class (bad idea), the derived class function won't prevail when applied on an object accessed via a reference to the base class.
http://ideone.com/CfejwQ


> is there a fix for that error

The fix was given in the first reply http://www.cplusplus.com/forum/beginner/110698/#msg604376
(std::bitset<> is a template.)
Last edited on
Aha, well this changes things a bit. I had assumed that bitset was a class. I've been reading up on templates, and concluded that I CAN extend a bitset with a class (not a struct), which was what I wanted to know. And I understand your third example, where I would then add methods to my class that would then change the private field impl. And I understand that the keyword using in the second example means you're doing name hiding, thus making sure that the method called will be in the child class of any method I choose to define there that are also in the bitset class.

But since you say that bitset is not made for inheritance, why do you still extend it in the second example? I see that it becomes private, but what difference does that make when it's still an extension?

And then there's the matter of the part in the sharp brackets. From what I've read about templates, they are for specifying functions that can handle all kinds of different data types. But for bitset, it's just a size_t integer. So how come it's not just a class that has NBITS as a parameter instead?

And in my case my LockedBitSet will be always of size 50. When using your code with my class, I then get the error 'template used without template parameters' for my cpp file. Is there a way I can specify the size to be 50 in the header file, so I don't have to add the brackets to every method in the cpp file?
> I see that it becomes private, but what difference does that make when it's still an extension?

See: http://www.gotw.ca/publications/mill06.htm



> But for bitset, it's just a size_t integer.
> So how come it's not just a class that has NBITS as a parameter instead?

Primarily for performance reasons, when NBITS is a constant known at compile time.

For a bitset, where the number of bits can be specified at run time, see boost::dynamic_bitset<>
http://www.boost.org/doc/libs/1_54_0/libs/dynamic_bitset/dynamic_bitset.html



> And in my case my LockedBitSet will be always of size 50. When using your code with my class,
> I then get the error 'template used without template parameters' for my cpp file.
> Is there a way I can specify the size to be 50 in the header file,
> so I don't have to add the brackets to every method in the cpp file?

Define members of a template class in the header file.

For cpp files, where the class is used, we can provide a type alias.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template < std::size_t NBITS = 50 > // 50 is the default value
struct basic_lockable_bitset 
{
    // ...

    private: std::bitset<NBITS> bs ;
};

// lockable_bitset is an alias for basic_lockable_bitset<> 
// (with the default number of bits - 50 in this case )
 
typedef basic_lockable_bitset<> lockable_bitset ;
// and / or
using lockable_bitset = basic_lockable_bitset<> ; // C++11 


And then, in your cpp file:
lockable_bitset my_bitset ;


If you want to commit your design to: we will never, ever, have to use a lockable_bitset with anything other than 50 bits, then don't make it a template at all:

1
2
3
4
5
6
7
8
9
struct lockable_bitset 
{
    static constexpr std::size_t NBITS = 50 ;
    // enum { NBITS = 50 } ; // C++98

    // ...

    private: std::bitset<NBITS> bs ;
};
Last edited on
Alright, but you're using your design suggestions as the basis for your solutions. I'm still extending the template with my class in my code. I'm not saying that will be the final design, you have brought up a lot of good points as to why it shouldn't, but that is what I'm debugging right now, and I need to learn how to fix those errors first, before I move on to choosing a different design. So using this code as my header file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef LOCKABLEBITSET_HPP_
#define LOCKABLEBITSET_HPP_

#include <bitset>

namespace pub {
	template <std::size_t NBITS> class LockableBitSet:public std::bitset<NBITS> {
		private:
			bool locked = false;
		public:
			void lock();
			bool isUnlocked();
	};
}

#endif 


how do I add the 50, so I can use this code for my cpp file.

1
2
3
4
5
6
7
8
9
10
11
#include "LockableBitSet.hpp"

namespace pub {
	void LockableBitSet::lock() {
		locked = true;
	}

	bool LockableBitSet::isUnlocked() {
		return !locked;
	}
}


That is all I want to know, as long as I don't get more errors when I've fixed this one.

Oh, and I did try using <std::size_t NBITS = 50> in my header file, but that still gives me the same error in my cpp file.

Edit: Well, I checked your link, but it doesn't explain why private inheritance is better than public, that's in part 2 though, which can be read here.

http://www.gotw.ca/publications/mill07.htm

I can't say that I agree with the reasoning, in the Square is a Rectangle example, if you have a field of type Rectangle, then you only need to know it's a rectangle, and if you have one of type Square, you only need to know that it's a Square, that a Rectangle field that contains a Square object which gets both its height and width set at the same time, well I don't see how that can possibly be important, since you only need to know that it does everything a Rectangle would do.

BUT I recognize that in C++, public inheritance is to be avoided at pretty much all costs, so I will take it to heart. I just don't understand it, nor agree with it. But I will follow it.
Last edited on
> BUT I recognize that in C++, public inheritance is to be avoided at pretty much all costs,
> so I will take it to heart.

No.

Public inheritance is to be avoided at pretty much all costs if
a. the base class is not designed for inheritance
b. there would be a violation of the Liskov Substitution Principle



> So using this code as my header file ...
> how do I add the 50, so I can use this code for my cpp file. ...

Make LockableBitSet a non-template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef LOCKABLEBITSET_HPP_
#define LOCKABLEBITSET_HPP_

#include <bitset>

namespace pub {
        class LockableBitSet : public std::bitset<50> {
		private:
			bool locked = false;
		public:
			void lock();
			bool isUnlocked();
	};
}

#endif  
Well well, that got rid of all errors. So now I can focus on redesigning my project. It's something that I've originally made in Java, where inheriting makes the most sense to me, but since I need to use it for BOINC, I have to adapt it to C++, which has a lot of different design principles, like that principle you mention, which I have never heard of before.

Either way, I owe you a big thank you for helping me out so much, and now I've got a lot of reading material, so I can learn how to best code in C++, so it's been a good exercise to try and get this to compile. Thank you once again.
Topic archived. No new replies allowed.