Click here to Skip to main content
15,881,172 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm trying to call initCapture() that's declared pure virtual in LexContext. I'm trying to call it indirectly in ArduinoLexContext by way of StaticLexContext<S> which overrides it.

I get

LexContext.hpp:316:25: error: there are no arguments to 'initCapture' that depend on a template parameter, so a declaration of 'initCapture' must be available [-fpermissive]



See the code in "What have you tried?"

I've been at this for too long and I need another set of eyes. I'm missing something easy. I know it.

What I have tried:

C++
#include <cstdint>
#include <ctype.h>
#include <stdlib.h>
namespace lex {
  // represents a cursor and capture buffer over an input source
  class LexContext {
      int16_t _current;
      unsigned long int _line;
      unsigned long int _column;
      unsigned long long _position;
    protected:
      // reads a character from the underlying device
      // read() should return EndOfInput if no more data is available,
      // and Closed if the underlying source has been closed, where
      // applicable
      virtual int16_t read()=0;
      // called to initialize the capture buffer
      virtual void initCapture()=0;
    public:
      ...

  };
// represents a LexContext with a fixed size buffer
  template<const size_t S> class StaticLexContext : virtual public LexContext {
    char _capture[S];
    size_t _captureCount;
    protected:
      // initializes the capture buffer
      void initCapture() override {
        *_capture=0;
        _captureCount=0;

      }
    public:
      StaticLexContext() {
            
      }
      // the capacity of the capture buffer (not including the trailing NULL)
      size_t captureCapacity() override { return S-1; }
      // the count of characters in the capture buffer
      size_t captureCount() const override {return _captureCount;}
      // returns a pointer to the capture buffer
      char* captureBuffer() override {return _capture;}
      // clears the capture buffer
      void clearCapture() override {
        _captureCount = 0;
        *_capture=0;
      }
      // captures the character under the cursor if any
      // returns true if a character was captured.
      bool capture() override {
        if (Closed!=current() && EndOfInput != current() && BeforeInput != current() && (S - 1) > _captureCount)
        {
          _capture[_captureCount++] = (uint8_t)current();
          _capture[_captureCount] = 0;
          return true;
        }
        return false;
      }

  };
#ifdef ARDUINO
  // represents a fixed length LexContext for the Arduino built on the Arduino SDK's Stream class
  template<const size_t S> class ArduinoLexContext : public StaticLexContext<S> { 
        Stream* _pstream;
    protected:
        // reads a character from the stream
        int16_t read() override {
            if(!_pstream)
              return LexContext::Closed;
            return _pstream->read();
        }
    public:
      ArduinoLexContext() {
            
      }
        // initializes the lexcontext with a stream
        bool begin(Stream& stream) {
            _pstream = &stream;
            initCapture(); // compile error!
            return true;
        }
    };
#endif
}
Posted
Updated 13-Dec-20 5:24am
v2
Comments
Richard MacCutchan 13-Dec-20 10:17am    
I have always had problems with this, but you are trying to override a pure virtual function in your template class. I think it needs to override an actual implementation.
honey the codewitch 13-Dec-20 10:32am    
nah it should be able to forward precisely *because* it's virtual. there's a vtbl in play so it just needs to find the function.

Turns out the compiler was looking for a global function called initCapture().

Since it's part of a template there's a 2 phase resolution process in C++ and it wasn't picking it up as part of the class.

So if you do this->initCapture() it all works fine. It gives the compiler what it needs to look in the right place (the base class) for the function.
Richard MacCutchan 13-Dec-20 10:36am    
I told you I had problems with it. I came very late to templates and still have to think long and hard whenever I (try to) use them.
honey the codewitch 13-Dec-20 10:37am    
Totally. They can be frustrating at times, but Accelerated C++ changed my life and I do a lot of generic programming now. Less so on Arduino stuff but still.
Richard MacCutchan 13-Dec-20 10:47am    
Since my livelihood no longer depends on my skills/knowledge there is less incentive to study it as deeply as I might otherwise. And a 75 year old brain takes considerably longer to absorb stuff. :(

The problem isn't the protected-ness. The problem is that ArduinoLexContext derives from a template class. The compiler sees initCapture(); and says, "Is this a member function derived from a base class? Or is it a global function? I'm going to assume it's a global function. Error: No global function called initCapture." (There might be a specialization template<> StaticLexContext<0> { /* doesn't derive from LexContext, no initCapture method */ }.) You need to help out the compiler and write this->initCapture() to say "The initCapture method is coming from my base class, trust me."
– Raymond Chen @ StackOverflow

Thanks Raymond.
 
Share this answer
 
Yeah. Mixing inheritance and templates is a terrible idea in the first place (that is is why STL does not use it) for the reasons that the templates are compile time constructs where inheritance of virtual functions is a run time construct. Mixing the two can lead to an incredibly complicated spaghettization of the final generated code.
 
Share this answer
 
Comments
honey the codewitch 13-Dec-20 11:29am    
Normally I don't find much occasion to mix them, but I wanted a more compilery, less preprocessory way of defining a maximum capacity for a fixed length array.

I'm not aware of a better solution to the problem than what I've done above, in this particular instance. The code difficulty is limited because the class isn't that complicated. This was one wrinkle, and it was a compiler SNAFU. A good reason not to use it sure *if a better replacement can be had* but I'm not aware of one for this case.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900