Attempting to use a Template instead of an Overloa

2019-07-06 10:59发布

问题:

I'm trying to write a function that can Shift out data to 74HC595 shift registers which can shift out 8, 16, and 32 bit values.

Using an overloaded function, I have this:

/**********************************************************************************
* Software SPI Pin Settings
*********************************************************************************/
#define SPIPINPORT  PORTB   //The Port that the Pins are on.  
#define LatchPin    2   //_RCLK  Shift register clock pin       
#define DataPin     3   //SER DS Serial data input              
#define ClockPin    5

/**********************************************************************************
* Preproccesor PIN to PIN Mask
*********************************************************************************/
#define LATCHMASK   (1 << LatchPin) 
#define MOSIMASK    (1 << DataPin)              
#define CLOCKMASK   (1 << ClockPin) 

/**********************************************************************************
* Macros
*********************************************************************************/
#define tggl(port,bit) (port)^=(1<<(bit))
#define LATCH   (SPIPINPORT &=~ LATCHMASK) 
#define unLATCH (SPIPINPORT |= LATCHMASK)  
#define PULSE   { tggl(SPIPINPORT,ClockPin); tggl(SPIPINPORT,ClockPin); }


void zShiftClass::ShiftOut(uint8_t value)
{
    LATCH;
    for (uint8_t i = 0; i <= 7; i++) 
    {   
        if( !!(value&(1<<i)) == true)   //If value is not a 1, turn off MOSIMASK
        { SPIPINPORT |= MOSIMASK; } 
        else    
        { SPIPINPORT &= ~MOSIMASK; }        

        PULSE;  //Pulse the Clock
    }
    unLATCH;
}

void zShiftClass::ShiftOut(uint16_t value)
{
    LATCH;
    for (uint8_t i = 0; i <= 15; i++) 
    {   
        if( !!(value&(1<<i)) == true)   //If value is not a 1, turn off MOSIMASK
        { SPIPINPORT |= MOSIMASK; } 
        else    
        { SPIPINPORT &= ~MOSIMASK; }        

        PULSE;  //Pulse the Clock
    }
    unLATCH;
}


void zShiftClass::ShiftOut(uint32_t value)
{
    LATCH;
    for (uint8_t i = 0; i <= 31; i++) 
    {   
        if( !!(value&(1<<i)) == true)   //If value is not a 1, turn off MOSIMASK
        { SPIPINPORT |= MOSIMASK; } 
        else    
        { SPIPINPORT &= ~MOSIMASK; }        

        PULSE;  //Pulse the Clock
    }
    unLATCH;
}

And I want to use this template to replace these functions:

template<typename TYPE>void Shift(TYPE value)
{
    uint8_t loops = (( 8 * sizeof(value) ) - 1 );

    LATCH;
    for (uint8_t i = 0; i <= loops; i++) 
    {   
        if( !!(value&(1<<i)) == true)   //If value is not a 1, turn off MOSIMASK
        { SPIPINPORT |= MOSIMASK; } 
        else    
        { SPIPINPORT &= ~MOSIMASK; }        

        PULSE;  //Pulse the Clock
    }
    unLATCH;
}

When I compile, I get the following errors:

 Compiling 'zLEDArray' for 'Arduino Uno' 
 zLEDArray.ino : variable or field 'Shift' declared void 
 zLEDArray.ino : 'TYPE' was not declared in this scope
 Error compiling

What am I doing wrong?

回答1:

Okay, this falls in the category of "beware of dev tools bearing gifts". The Arduino sketch tool is your problem. If you turn on verbose compiler output on the preferences menu, you will get some insight into what happens. With your code, I can duplicate your error. When compiling a test project called template1, the same error is reported, but now can see the compiler command line:

D:\arduino-dev\arduino-1.0.3\hardware\tools\avr\bin\avr-g++ -c ...yada yada
more yada... e:\Temp\build3528223623599856131.tmp\template1.cpp ...
template1:14: error: variable or field 'Shift' declared void
template1:14: error: 'TYPE' was not declared in this scope

The key point is that .CPP file. That is a file that the dev environment constructs from your .INO and is what is the actual input to the compiler. If you go grab that file, you will see all your code with some bonus lines included:

#include "Arduino.h"
void Shift(TYPE value);
void setup();
void loop();

The build tool added for you, 4 lines:

  • the Arduino header (because nobody remembers this)
  • 3 forward declarations for functions that it figured out by parsing code

The attempt at producing a forward declaration from the function template is incorrect, and produces the code that results in the compiler error.

The solution is to move the template out from the .INO file.

  1. Create a library folder, say T1.
  2. Create a .H file in that folder with the template code, say tspi.h.
  3. Import the library to your project.
  4. Make sure the #include line is after the first line of code in your .INO (more weirdness - the tool will insert a #include "Arduino.h" after all the comments but before first line of code. If you leave your include at the top of the .INO file, it will be processed before the Arduino header)


回答2:

You can get rid of the error by adding the correct forward declaration in your ino file. The inuntuitive thing is that you must also do this if you define the function before you use it:

template <typename TYPE> void Shift(TYPE value);

// you may use the function here or you can have the declaration
// immediately before the definition

template<typename TYPE>void Shift(TYPE value)
{
    // your implementation
}

The explanation why this is the case is in jdr5ca's answer. Thanks for clarifying, I found this out by trial and error.