指向成员变量的引用/指针作为模板形参

C++: Reference/pointer to member variable as template parameter

本文关键字:形参 指针 成员 变量 引用      更新时间:2023-10-16

首先,我有这样的东西:

class Test {
    std::vector<int> a, b;
    void caller(...) { callee(...); }
    void callee(...) { /* Do stuff with 'a' */ }
}

我想要的是一个与callee完全相同的函数但是对于向量b。要做到这一点,有两个明显的解决方案:

  • 传递矢量ab作为参数。然而,callee是一个可以进行数百次调用的递归函数,将向量作为参数传递只是不必要的开销。
  • 复制函数callee并使用矢量b,这将是最好的选择,尽管callee是一个相当长的函数,我会有很多重复的代码。

出于好奇,我去找模板部分,我注意到可以用于

左值引用类型

指针类型指向成员类型 的指针

所以我试着这样做:

class Test {
    std::vector<int> a, b;
    void caller(...) { callee<a>(...); }
    template <std::vector<int> &x> void callee(...) { /* Do stuff with 'x' */ }
}

但是我得到

错误:在常量表达式

中使用' this '

是否有任何方法来实现这一点,无论是引用或指针?

顺便说一下,我想要的可以看作是一个函数作用域的#define

数组甚至元组,但不喜欢老式的指向成员的指针?

class Test {
    std::vector<int> a, b;
    void caller(/*...*/) { callee<&Test::a>(/*...*/); }
    template <std::vector<int> Test::*vec>
    void callee(/*...*/) { /* Do stuff with `(this->*vec)` */ }
};

不能使用对数据成员的引用作为模板参数:模板是编译时的,this的值直到运行时才知道。换句话说,对于类型为Test的每个运行时对象,您需要一个单独的实例化(单独的二进制代码)。

可以做的是将ab替换为一个数组,并通过索引将callee模板化为这个数组:

class Test {
    std::array<std::vector<int>, 2> ab;
    void caller(...) { callee<0>(...); }
    template <size_t idx>
    void callee(...) { /* Do stuff with 'ab[idx]' */ }
}

这样,您只获得callee的两个实例化(一个用于0,一个用于1),索引在编译时完成(或至少是可行的)。

直接使用facade:

class Test {
    std::vector<int> a, b;
    void caller_a(...) { callee(a); }
    void caller_b(...) { callee(b); }
    void callee(std::vector<int> &a_or_b, ...) {
    }
}

callee()将引用它的形参,该形参将作为一个或另一个类成员传入。

与@Angew的回答相同,您也可以使用std::tuple,这很有趣,因为使用tuple您还可以在被调用函数中使用不同类型的容器:

class Test {
    std::tuple<std::vector<int>, std::list<int> > ab;
    void caller(...) { callee<0>(...); }
    template <size_t idx>
    void callee(...) { 
    ...
    auto aIt = std::get<idx>(ab).begin(); // gets either the vector or the list depending on template value
    ...
    }
}