Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

lloyddean

macrumors 65816
Original poster
May 10, 2009
1,047
19
Des Moines, WA
OK a bad case of code blindness.

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

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

results in -
Code:
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.


Code:
/* =====================================================================================================================
 * 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

Code:
/* =====================================================================================================================
 * 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

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
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

macrumors 65816
Original poster
May 10, 2009
1,047
19
Des Moines, WA
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.
 
Last edited:

chown33

Moderator
Staff member
Aug 9, 2009
10,751
8,423
A sea of green
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

macrumors newbie
Apr 8, 2009
27
0
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:

Code:
template <const int CAPACITY>
bool circular_queue_t<CAPACITY>::dequeue(uint8_t& element)
{
    .
    .
    .
}
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.