未知的类方法回调,它接受0个参数并返回可转换为int的类型

时间:2014-12-28 01:49:56

标签: c++ templates callback

我正在制作协议界面。该协议应该用于从设备发送ADC数据。各种微控制器具有允许ADC读取的库,但当然,它们是不同的类型。

例如,Nucleo中的模拟阅读:

AnalogIn ain(A0); 
unsigned short value = ain.read_u16();

和Arduino:

int analogPin = 3;
int val = analogRead(analogPin);

虽然这种方法返回不同类型并且实际上是完全不同的类型,但它们返回相同的数据。

我的问题是,是否可以创建一个接受这两个函数作为回调的类,并将其返回值返回为int

像这样:

class ThisIsNotReal {
  public:
    ThisIsNotReal(<ANY TYPE THAT CAN CONVERT TO INT HERE> (*cb)() ) {
      callback = cb;
    }
    int getVal() {
       return callback();
    }

  private:
    <ANY TYPE ... (some super magical template? anyone?)> (*cb)()

}

当然,我的目标是在不编写太多代码的情况下使用Arduino兼容代码。另外,我想学习一些模板魔术。

3 个答案:

答案 0 :(得分:1)

似乎std::function和lambda可能会有所帮助,例如:

AnalogIn ain(A0); 
std::function<int()> AdcRead = [ain](){ return ain.read_u16(); };

const int analogPin = 3;
std::function<int()> AdcRead = [analogPin](){ return analogRead(analogPin); };

答案 1 :(得分:1)

除非你为使用回调的所有目标设备配备了C ++ 11编译器,否则不一定非常简单。这是因为调用各种函数所需的存储要求和参数之间存在差异。因为如果这样,您可以考虑创建一个用于从IO端口读取输入的公共接口,然后为每个目标设备/平台提供唯一的实现。这将允许您具有初始化IO相关对象以及从IO端口读取的常用方法。

即使你的目标平台上有一个C ++ 11编译器,如果它们被证明会影响性能,那么使用std::functionvirtual函数可能也不可取(或者甚至是一个选项)。类似下面的代码可能更加可行,因为它很简单。

#if defined (IS_NUCLEO)
struct InputDevice
{
    InputDevice(int port) : device(port) {}

    int read() const
    {
        return static_cast<int>(device.read_u16());
    }

    AnalogIn    device;
};
#endif

#if defined(IS_ARDUINO)
struct InputDevice
{
    InputDevice(int port) : port(port) {}

    int read() const { return analogRead(port); }

    int port;
};
#endif

我建议你定制它以满足你的确切要求。

答案 2 :(得分:0)

ThisIsNotReal应存储ConvertFuncToIntBase* conv类型的指针并调用conv->getVal()。您将通过在makeIntConverter的构造函数中调用ThisIsNotReal来创建适当的实例。 makeIntConverter如果传递给它的函数的返回类型不能转换为int,则不会编译。虽然下面的解决方案使用需要C ++ 11的std::enable_ifstd::is_convertible,但您可以使用类似的C ++ 03 Boost方法。

class ConvertFuncToIntBase
{
public:
virtual int getVal() = 0;
virtual ~ConvertFuncToIntBase(){}
};

template <typename T>
class ConvertFuncToInt : ConvertFuncToIntBase
{
public:
ConvertFuncToIntLand(T (*cb)()) : callback(cb)
{
}

int getVal()
{
 return (int)callback();
}

private:
T (*callback)();
};

template <typename T, typename = typename std::enable_if<std::is_convertible<T, int>>::type>
std::unique_ptr<ConvertFuncToIntBase> makeIntConverter(T (*cb)())
{
 return std::unique_ptr<ConvertFuncToIntBase>(new ConvertFuncToInt<T>(cb));
}