1

Context: I am making a switch debouncing wrapper class for InterruptIn called Switch. Switch will allow a user to attach their own function which should be called-back when a real-world switch is pressed and debounced. I'm using Eclipse C++ with the arm-none-eabi-* toolchain.

First off, I found three ways of implementing callbacks with mbed:

  1. The FunctionPointer class, which is deprecated by ARM, but has some documentation (with broken hyperlinks to information I think I need).

  2. Callback<void()>, the compiler informs me this is The Right WayTM to do callbacks when trying to use deprecated FunctionPointer, but no documentation?

  3. event_callback_t, no documentation, and the function responsible for calling the user's attached function takes an int as a parameter?

I'll be using the Callback<void()> way to show the problem I'm having, but all three ways produce the same compile error.

Switch.h:

#ifndef MBED_SWITCH_H
#define MBED_SWITCH_H

#include "mbed.h"

class Switch {
    private:
        Callback<void()> callback_press_;
        InterruptIn switch_;

        //redacted some debouncing stuff

    public:
        Switch(PinName pin, bool isActiveHigh);
        Switch(PinName pin, bool isActiveHigh, int samplePeriod_us, int sampleCount);

        void attachPress(Callback<void()>); //THE PROBLEM FUNCTIONS
        template<typename T, typename F>
        void attachPress(T* object, F function);
};

#endif

Switch.cpp:

#include "Switch.h"
#include "CustomNames.h"

 // redacted constructors here

 //  redacted debouncing functions here

 // for attaching a function not associated with any particular class
void Switch::attachPress(Callback<void()> function) {
    callback_press_.attach(function);
}

 // for attaching a member function of some other class
template<typename T, typename F>
void Switch::attachPress(T* object, F function) {
    callback_press_.attach(object, function);
}

The Problem

Everything compiles, links, and works fine in the real world if I use the first candidate function attachPress(Callback<void()> function) to attach a function not associated with any particular class.

However, when I try to attach a specific member function "testfunc1(void)" of another class "Test" with the second candidate function, I get the following error (from the linker, I think):

Test.o: In function `Test::Test()':
Test.cpp:(.text._ZN4TestC2Ev+0x1e): undefined reference to `void Switch::attachPress<Test, void (Test::*)()>(Test*, void (Test::*)())'
/home/yankee/programming_projects/cpp-eclipse/SO_EXAMPLE/Makefile:97: recipe for target 'HW4_RACE.elf' failed
collect2: error: ld returned 1 exit status
Makefile:21: recipe for target 'all' failed
make[1]: *** [HW4_RACE.elf] Error 1
make: *** [all] Error 2

03:10:35 Build Finished (took 165ms)

Why is this giving me "undefined reference", and is there a way to fix it?

Yankee
  • 1,011
  • 1
  • 9
  • 18

1 Answers1

2

Templated classes and functions are not instantiated until they are used.

It means that, the translation unit which uses the template classes and function needs the full code of that template.

In this case, simply move:

template<typename T, typename F>
void Switch::attachPress(T* object, F function) {
    callback_press_.attach(object, function);
}

from Switch.cpp to Switch.h will work.

Danh
  • 5,916
  • 7
  • 30
  • 45