c++ - 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接

标签 c++ templates pointer-to-member

考虑以下代码片段:

#include <cstdint>
#include <iostream>

struct Foo {
    Foo() : foo_(0U), bar_(0U) {}

    void increaseFoo() { increaseCounter<&Foo::foo_>(); }
    void increaseBar() { increaseCounter<&Foo::bar_>(); }

    template <uint8_t Foo::*counter>
    void increaseCounter() { ++(this->*counter); }

    uint8_t foo_;
    uint8_t bar_;
};

void callMeWhenever() {
    Foo f;  // automatic storage duration, no linkage.
    f.increaseFoo();
    f.increaseFoo();
    f.increaseBar();

    std::cout << +f.foo_ << " " << +f.bar_;  // 2 1
}

int main() {
    callMeWhenever();
}

我的第一个猜测是这是格式错误的,因为 callMeWhenever() 中的 f 具有自动存储持续时间,并且其地址在编译时未知time,而 Foo 的成员模板函数 increaseCounter() 是使用指向 Foo 的数据成员的指针以及给定的内存表示来实例化的。类类型是编译器特定的(例如填充)。然而,从 cppreference / Template parameters and template arguments ,afaics,这是格式良好的:

Template non-type arguments

The following limitations apply when instantiating templates that have non-type template parameters:

[..]

[until C++17] For pointers to members, the argument has to be a pointer to member expressed as &Class::Member or a constant expression that evaluates to null pointer or std::nullptr_tvalue.

[..]

[since C++17] The only exceptions are that non-type template parameters of reference or pointer type [added since C++20: and non-static data members of reference or pointer type in a non-type template parameter of class type and its subobjects (since C++20)] cannot refer to/be the address of

  • a subobject (including non-static class member, base subobject, or array element);
  • a temporary object (including one created during reference initialization);
  • a string literal;
  • the result of typeid;
  • or the predefined variable __func__.

这是如何工作的?编译器(通过直接或间接,例如上述标准要求)是否需要自行对此进行排序,仅存储成员之间的(编译时)地址偏移量,而不是实际地址?

即/例如,是指向 Foo::increaseCounter() 中数据成员非类型模板参数 counter 的编译时指针(对于两个特定的每一个)指向数据成员实例的指针)只是 Foo 任何给定实例的编译时地址偏移量,稍后将成为 Foo 每个实例的完全解析地址,即使目前还没有在 callMeWhenever() 的 block 作用域中分配诸如 f 之类的值?

最佳答案

Is the compiler (by direct or indirect, e.g. the above, standard requirements) required to sort this out by itself, storing only (compile-time) address offsets between the members, rather than actual addresses?

差不多了。即使在编译时上下文之外,它也是一个“偏移量”。指向成员的指针与常规指针不同。它们指定成员,而不是对象。这也意味着有关有效指针目标的措辞与指向成员的指针无关。

这就是为什么要从它们中生成实际的左值,必须用引用对象的东西来完成图片,就像我们在 this->*counter 中所做的那样。如果您尝试在需要常量表达式的地方使用 this->*counter ,编译器会提示,但它会是关于 this 的,而不是 计数器

它们独特的性质使得它们能够无条件地成为编译时间常量。编译器没有必须将任何对象检查为有效目标。

关于c++ - 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59665325/

相关文章:

c++ - 使用带有宏的 decltype 显式实例化类成员函数

c++ - 将字节数组转换/转换为地址

django - 如何加密django模板中url中传递的参数

c++ - Ptr-to-member 模板参数的 Friend 语法

c++ - 控制台上的不同输出打印标准输出/重定向到文件

c++ - 使用 Phonon 播放 mp4 视频

c++ - 特化的隐式实例化

templates - 了解jsf ui的用途 :composition

c++ - 使用指向成员的指针读取 cons 对象字段的值

c++ - 错误: a pointer to a bound function may only be used to call the function