首页 > 解决方案 > 在模板方法c ++中传递结构参数

问题描述

我在将参数传递给类模板时遇到问题

struct Car {
    int id;
    char *model;
    int date;
    int cost;
};

template <class T>
class Set
{
private:
    int *a;
    int _size;
    map<int, T> data;
public:

    //some methods before

    void insert(T x)
    {

        int num;
        if (std::is_same<T, Car>::value)
            num = x.id;
        if (num >= 0 && num < (_size << 5))
            throw "Element is out of set size!";
        a[num / 32] = a[num / 32] | (1 << (num % 32));
        if (std::is_same<T, Car>::value)
            data.insert(make_pair(num, x));
    }
};

我的insert方法应该同时接受int类型和Car结构。但是 Visual Studio 说我有编译错误num = x.id;应该x是一个类、结构或联合。我可以传递指向这个函数的指针,但我不能传递像class.insert(5). 我该如何解决它,或者如何使方法既接受指向结构变量的指针又接受常规变量的指针,而无需对其中一种类型进行另一种规范?

标签: c++classtemplates

解决方案


是的,这是很多人都在努力解决的问题。让我们看看你的模板方法被剪断:

void insert(T x)
{
    int num;
    if (std::is_same<T, Car>::value)
        num = x.id;
    //...

这里的问题是if语句在运行时进行语义评估(即使编译器可以优化分支,因为它会在编译时知道值),因此,编译器需要“假装”为两个分支生成代码。附带说明一下,当不采用分支时,您的num保持统一化,这是未定义的行为。

在您的情况下,这意味着即使T不是Car,语义上的代码仍然需要为num = x.id. 显然,int.id这不是一个有效的说法。

要使用 C++17 解决此问题,您将使用if constexpr

if constexpr (std::is_same<T, Car>::value) //...

Constexpr ifs 保证在编译时被评估,属于未采用分支的代码不会被评估。

在 C++17 之前的世界中,您通常可以使用标签调度或 SFINAE。我总是更喜欢标签调度,因为我认为它比 SFINAE 更直接。标签调度依赖于使用函数重载,在你的情况下会是这样的(因为不清楚你的代码在传递时会做什么int,我会假装你需要设置num为 int 传递:

int get_id(const Car& car) {
    return car.id;
}

int get_id(int v) {
    return v;
}

void insert(const T& t) {
    int num = get_id(t);
    // ...

请注意,在这种特殊情况下,它甚至不是标签调度,因为情况非常简单。


推荐阅读