【问题标题】:Invalid conversion of pointer in template class instantiation模板类实例化中的指针转换无效
【发布时间】:2019-09-16 13:35:34
【问题描述】:

我在我的 .h 文件中声明了以下模板类

enum class Hal_uart_id
{
    Uart = 0,
    Usart0,
    Usart1,
    Usart2,
    Usart3,
    UsbUart,
};

template <class T> 
class HalUART
{
    public:
        HalUART(Hal_uart_id uart_id);
    private:
        Hal_uart_id _uart_id;
        T* _p_uart; 
}

在我的 .cpp 文件中,我按如下方式实现类构造函数:

#include "hal_uart_common.h"
#include "Arduino.h"

template <class T> 
HalUART<T>::HalUART(Hal_uart_id id)
{
    _uart_id = id;
    switch (_uart_id)
    {
        case Hal_uart_id::Uart:
            _p_uart = &Serial;
            break;
        case Hal_uart_id::UsbUart:
            _p_uart = &SerialUSB;
            break;
        case Hal_uart_id::Usart0:
            _p_uart = &Serial1;
            break;
        case Hal_uart_id::Usart1:
            _p_uart = &Serial2;
            break;
        case Hal_uart_id::Usart3:
            _p_uart = &Serial3;
            break;
        default:
            break;
    }
}

在 .cpp 文件的末尾,我使用 USARTClass 类实例化模板类

template class HalUART<USARTClass>;

我收到以下编译错误,我不明白为什么或如何解决它:

src/hal/uart/hal_uart_sam3x.cpp: In instantiation of 'HalUART<T>::HalUART(Hal_uart_id) [with T = USARTClass]':
src/hal/uart/hal_uart_sam3x.cpp:58:16:   required from here
src/hal/uart/hal_uart_sam3x.cpp:23:21: error: invalid conversion from 'UARTClass*' to 'USARTClass*' [-fpermissive]
             _p_uart = &Serial;
             ~~~~~~~~^~~~~~~~~
src/hal/uart/hal_uart_sam3x.cpp:26:21: error: cannot convert 'Serial_*' to 'USARTClass*' in assignment
             _p_uart = &SerialUSB;
             ~~~~~~~~^~~~~~~~~~~~
*** [.pio/build/due/src/hal/uart/hal_uart_sam3x.cpp.o] Error 1

这些对象在 Arduino 核心中定义

UARTClass Serial;
USARTClass Serial1;
USARTClass Serial2;
USARTClass Serial3;
Serial_ SerialUSB;

有关 UART/USART 类和对象定义,请参阅: https://github.com/arduino/ArduinoCore-sam/blob/master/cores/arduino/UARTClass.h https://github.com/arduino/ArduinoCore-sam/blob/master/cores/arduino/UARTClass.cpp

https://github.com/arduino/ArduinoCore-sam/blob/master/cores/arduino/USARTClass.h https://github.com/arduino/ArduinoCore-sam/blob/master/cores/arduino/USARTClass.cpp

https://github.com/arduino/ArduinoCore-sam/blob/master/cores/arduino/USB/USBAPI.h https://github.com/arduino/ArduinoCore-sam/blob/master/cores/arduino/USB/CDC.cpp

【问题讨论】:

  • 您很可能混合了继承对象和继承对象的类型,因此您的指针分配是非法的。但是,为了确保我需要在构造函数中使用 Serial、SerialUSB 和其他定义以及 USARTClass。
  • 请提供minimal reproducible example。您没有提供Serial 的定义,所以我们无法确定它是什么。
  • @L.F.:与 cpp 中的模板无关,因为 OP 显式实例化了该类。
  • @Jarod42 OP 可能在另一个翻译单元中使用了这个模板类,对吧?

标签: c++ pointers templates


【解决方案1】:

模板类型必须在编译时解决。使用template class HalUART&lt;UARTClass&gt;; 而不是USARTClass(一次class USARTClass : public UARTClass;)实例化您的类。而且,在Serial_ 的情况下,例如,使用if constexpr(仅限c++17)和std::is_same

case Hal_uart_id::UsbUart:
    if constexpr (std::is_same_v<T, Serial_>)
        _p_uart = &SerialUSB;
    break;

我建议在其他情况下也使用if constexpr,例如,一旦你用Serial_ 实例化你的类,那么你也可以template class HalUART&lt;USARTClass&gt;;

switch (_uart_id)
{
case Hal_uart_id::Uart:
    if constexpr (std::is_same_v<UARTClass, T>)
        _p_uart = &Serial;
    break;
case Hal_uart_id::UsbUart:
    if constexpr (std::is_same_v<T, Serial_>)
        _p_uart = &SerialUSB;
    break;
case Hal_uart_id::Usart0:
    if constexpr (std::is_same_v<USARTClass, T>)
        _p_uart = &Serial1;
    break;
case Hal_uart_id::Usart1:
    if constexpr (std::is_same_v<USARTClass, T>)
        _p_uart = &Serial2;
    break;
case Hal_uart_id::Usart3:
    if constexpr (std::is_same_v<USARTClass, T>)
        _p_uart = &Serial3;
    break;
default:
    break;
}

通过这种类型检查,您的switch 可能不再需要。尝试对此进行评估。

如有必要,请考虑使用std::is_base_of


如果 c++17 不可用,请尝试专门化您的功能:

template <class T>
HalUART<T>::HalUART(Hal_uart_id id) {}

template <>
HalUART<UARTClass>::HalUART(Hal_uart_id id) {
    if (id == Hal_uart_id::Uart)
        _p_uart = &Serial;
}
template <>
HalUART<Serial_>::HalUART(Hal_uart_id id) {
    if (id == Hal_uart_id::UsbUart)
        _p_uart = &SerialUSB;
}
template <>
HalUART<USARTClass>::HalUART(Hal_uart_id id) {
    if (id == Hal_uart_id::Usart0)
        _p_uart = &Serial1;
    else if (id == Hal_uart_id::Usart1)
        _p_uart = &Serial2;
    else if (id == Hal_uart_id::Usart3)
        _p_uart = &Serial3;
}

live example

【讨论】:

  • 谢谢,此解决方案适用于 C++ 11,但不幸的是,这是一个嵌入式系统,不支持 std::is_same_v 等 C++ 11 功能 希望还有其他方法吗?
  • 实际上适用于 C++17。您可以解决这个问题,专门针对您的课程。检查编辑。
  • 该解决方案完美运行。我实际上正在研究如何正确地专门化模板类,但你也为我做了这件事。真的很感激
猜你喜欢
  • 2012-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
相关资源
最近更新 更多