首页 > 解决方案 > 如何在编译时验证模板函数参数的类型

问题描述

我正在编写一个用于通信传感器数据的类,并且我想制作它,以便该类的用户不能使用不正确的数据类型来发送传感器数据。

我想像这样设置我的班级:

private:
    static const _sensor_bytes[] = {2, 4, ...};

public:
    enum sensor_name_t {
        SENSOR1 = 0,
        SENSOR2 = 1,
        ...
    };

    template<class T>
    void writeData(sensor_name_t sensor, T data){
        if _sensor_bytes[sensor] != sizeof(T){
            // Do not compile
        }
    }

例如,

int data = 30;
writeData(SENSOR1, data); // This would not compile because _sensor_bytes[0] = 2 and sizeof(int) = 4
writeData(SENSOR2, data); // This would compile because _sensor_bytes[1] = 4 and sizeof(int) = 4

我是否以正确的方式解决这个问题?如果是这样,我将如何完成此功能?

标签: c++

解决方案


您不能使用 function 执行此操作void writeData(sensor_name_t sensor, T data),因为sensor在运行时知道值,所以它不能通过在编译时验证并引发错误。

变体 1

您可以尝试使用std::enable_ifsensor从函数参数移动到模板参数并使用constexprfor _sensor_bytes。它需要编译器的 C++11 支持。

#include <cstdint>
#include <type_traits>

class Test {
private:
    static constexpr int _sensor_bytes[] = {2, 4};

public:
    enum sensor_name_t {
        SENSOR1 = 0,
        SENSOR2 = 1
    };

    template<int sensor,
             class T,
             typename = typename std::enable_if<(sizeof(T) == _sensor_bytes[sensor])>::type >
    void writeData(T data) {
        // Use 'sensor' and 'data' here
        // ...
    }
};


int main()
{
    Test test;

    uint16_t data1;
    uint32_t data2;
    test.writeData<Test::SENSOR1>(data1);
    test.writeData<Test::SENSOR2>(data2);
    //test.writeData<Test::SENSOR2>(data1); // Will not compile
    //test.writeData<Test::SENSOR1>(data2); // Will not compile
    return 0;
}

变体 2

如果您仍然需要在运行时传递两个函数参数,那么验证也应该在运行时完成:

  • 采用assert
  • 抛出异常
  • 返回一些错误代码

推荐阅读