Code Blindness

Discussion in 'Mac Programming' started by lloyddean, May 31, 2012.

  1. macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #1
    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
    
     
  2. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    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
     
  3. lloyddean, May 31, 2012
    Last edited: May 31, 2012

    thread starter macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #3
    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.
     
  4. macrumors 603

    Joined:
    Aug 9, 2009
    #4
    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.
     
  5. macrumors newbie

    Joined:
    Apr 8, 2009
    #5
    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)
    {
        .
        .
        .
    }
    
     
  6. thread starter macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #6
    RiskyMr, thanks!
     

Share This Page