PDA

View Full Version : Code Blindness




lloyddean
May 31, 2012, 11:47 PM
OK a bad case of code blindness.

I'm just not see why attempts at compiling the following code with -


clang++ -stdlib=libc++ -std=c++11 circular_queue.cpp


results in -

circular_queue.cpp:30:6: error: expected a class or namespace
bool circular_queue_t::dequeue(uint8_t& element)
^
circular_queue.cpp:91:6: error: expected a class or namespace
void circular_queue_t::report(std::ostream& os) const
^
2 errors generated.


The code compiled and worked fine until I pulled it into separate header and implementation files.



/* ==================================================================================================== =================
* File - circular_queue.h
* ---------------------------------------------------------------------------------------------------------------------
* Implements a circular queue of 2-bit values.
*
* <http://en.wikipedia.org/wiki/Circular_buffer>
*/

#ifndef circular_queue_H
#define circular_queue_H


/* ==================================================================================================== =================
* ---------------------------------------------------------------------------------------------------------------------
*/

#include <cstdint>

#ifndef NDEBUG

#include <iostream>
#include <iomanip>

#endif


/* ==================================================================================================== =================
* ---------------------------------------------------------------------------------------------------------------------
*/

template <const int CAPACITY>
class circular_queue_t
{
const int _capacity;

int _count;
int _head;
uint8_t _array[CAPACITY >> 2];

public:
circular_queue_t()
: _capacity(CAPACITY), _count(0), _head(0)
{}

bool dequeue(uint8_t& element);
bool enqueue(uint8_t const element);

bool is_empty() const { return (_count == 0); }
bool is_full() const { return (_count == _capacity); }
int count() const { return _count; }

#ifndef NDEBUG

void report(std::ostream& os) const;

#endif
};

#endif



/* ==================================================================================================== =================
* File - circular_queue.cpp
* ---------------------------------------------------------------------------------------------------------------------
* Implements a circular queue of 2-bit values.
*
* <http://en.wikipedia.org/wiki/Circular_buffer>
*
* clang++ -stdlib=libc++ -std=c++11 circular_queue.cpp -o circular_queue.o
*/

/* ==================================================================================================== =================
* ---------------------------------------------------------------------------------------------------------------------
*/

//#define NDEBUG

#include "circular_queue.h"


/* ==================================================================================================== =================
* ---------------------------------------------------------------------------------------------------------------------
*/

bool circular_queue_t::dequeue(uint8_t& element)
{
if ( ! is_empty() )
{
int index = (_head >> 2);
int dindex = (_head & 3);

element = ((_array[index] >> ((3 - dindex) << 1)) & 3);

_head = ((_head + 1) % _capacity);
_count--;

return true;
}

return false;
}


/* ==================================================================================================== =================
* ---------------------------------------------------------------------------------------------------------------------
*/

bool circular_queue_t::enqueue(uint8_t const element)
{
static uint8_t mask[] = { 0b00111111, 0b11001111, 0b11110011, 0b11111100 };

if ( ! is_full() )
{
int tail = ((_head + _count) % _capacity);
int index = (tail >> 2);
int dindex = (tail & 3);

_array[index] = (_array[index] & mask[dindex]) | ((element & 3) << ((3 - dindex) << 1));

_count++;

return true;
}

return false;
}


#ifndef NDEBUG

class StStreamFormatFlags
{
std::ostream& m_ostream;
std::ios_base::fmtflags m_flags;

public:
StStreamFormatFlags(std::ostream& str) : m_ostream(str), m_flags(str.flags())
{}

~StStreamFormatFlags()
{
m_ostream.flags(m_flags);
}
};

void circular_queue_t::report(std::ostream& os) const
{
using std::setfill;
using std::setw;

StStreamFormatFlags ffSave(os);

int count = _count;
int head = _head;

while ( count-- )
{
int index = (head >> 2);
int dindex = (head & 3);

int element = ((_array[index] >> ((3 - dindex) << 1)) & 3);

os << setw(4) << setfill(' ') << element;

head = ((head + 1) % _capacity);
}
}

#endif



lee1210
Jun 1, 2012, 12:47 AM
I can't see the issue immediately, but I would try:
1) Combine them again. Take out the include, put the contents of the .h file in its place, and try again. If it works, that seems odd, but let us know. If it does not work, you can stop blaming the division into different files.

2) you commented out #define NDEBUG. So you expect to include anything inside #ifndef NDEBUG blocks. Try commenting that back in. Try putting in all of those blocks unconditionally. Try removing all of those blocks completely. Let us know if anything changes in any of these cases.

-Lee

lloyddean
Jun 1, 2012, 12:59 AM
lee1210

Thanks for taking a look at it.

Uncommenting '#define NDEBUG' results in what would be expected - it drops complaining about 'circular_queue_t::report' since in was conditionally compiled.

Recombining everything into a single header file and including in a test application works as one would expect.

These are all things I tried before asking for a new set of eyes.

Any other suggestions.

I did forget to mention -

clang++ -v
Apple clang version 3.1 (tags/Apple/clang-318.0.58) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.4.0
Thread model: posix

EDIT: Maybe an attempt at a good nights rest will provide a solution.

chown33
Jun 1, 2012, 10:07 AM
Recombining everything into a single header file and including in a test application works as one would expect.

A single header? I would expect that to fail.

If you put implementation code in a header, then #include that header more than once, code gets duplicated at each #include site. This usually fails at link time (unless the implementation is static visibility).

Please post the single-file case that works.


Try removing things from the separated header/implementation files. Take out all the functions, both header declarations and code implementations. Take out all the member variables. Do the removals one at a time, recompiling after each removal. If it compiles, you just removed the problematic thing.

After all function and variable removals, there should be almost nothing but an empty class definition. Change the class name. If it still fails, post that code.

RiskyMr
Jun 1, 2012, 10:13 AM
In C++ if you provide a template member function definition in a .cpp file you need to precede it with the template<...> prefix.

So you would need to do something like this in your cpp file:


template <const int CAPACITY>
bool circular_queue_t<CAPACITY>::dequeue(uint8_t& element)
{
.
.
.
}

lloyddean
Jun 1, 2012, 12:10 PM
RiskyMr, thanks!