【问题标题】:Execute code once for each C++ class template instance为每个 C++ 类模板实例执行一次代码
【发布时间】:2014-12-07 16:48:59
【问题描述】:

好的,这很复杂。

我有一个多次实例化的 C++ 类模板。对于这些实例中的每一个,我都需要执行一个注册一些运算符的函数。在使用该模板实例的第一个对象之前,每个模板实例只需执行一次(这并不意味着它必须在编译时发生的实例化中执行)。

到目前为止,我是手动完成的。但这是一种痛苦。所以我想自动执行注册功能。

我目前的想法是在构造函数中调用一个受保护的注册方法。然而,每当构造类的实例时,这都需要(小)开销。由于经常这样做,我想避免这种开销。

我也尝试使用静态 RAII 帮助器成员,但如果未主动访问静态模板类成员,则不会构造它们,因此此尝试失败。

有没有一种方法可以在没有运行时开销的情况下在类模板实例化(通过函数或可能通过 RAII 辅助类)上执行代码?

【问题讨论】:

  • 通常模板在编译时而不是在运行时被实例化。你确定,你的问题是真的吗?
  • 是的。我不需要执行代码 at 实例化。我需要在第一次使用对象之前执行它。

标签: c++ templates c++11 class-template


【解决方案1】:

您可以添加一个静态数据成员,该成员将在其构造函数和析构函数中执行所需的任何操作。您可以放心地将其定义放入头文件中,因为只要它是模板,它只会被定义一次。唯一需要注意的是,要实例化它,您必须 odr-use 它。

template <typename T>
class Data {
public:
    Data() {
        std::cout << "creating Data<" << typeid(T).name() << '>' << std::endl;
    }
    ~Data() {
        std::cout << "destroying Data<" << typeid(T).name() << '>' << std::endl;
    }
};

template<typename T>
class A {
    static Data<T> data;
public:
    A() {
        // this is necessary for data to be instantiated
        (void)data;
    }
 };

// This also should be in a header
template<typename T>
Data<T> A<T>::data;

int main(){
    A<int> aInt;
    A<int> aInt2;
    A<float> aFloat;
}

Demo

编辑:这实际上有点不安全,因为在不同的翻译单元中创建静态对象的顺序是未指定的,因此例如在执行Data::Data() 时可能没有std::cout(所以不要在那里使用任何静态全局对象)。更安全的方法是在 A::A() 中调用静态函数,尽管它会引入一些开销:

template<typename T>
class A {
    static void createData() {
        static Data<T> data;
    }
public:
    A() {
        createData();
    }
};

【讨论】:

  • 太棒了!该解决方案对我有用!实际上,我尝试了 very 类似的东西,但没有成功,因为我忘记了“template Data A::data;”线。忘记添加那行时,我不应该得到某种错误吗?
  • 啊,还有一个……为什么是“(void)data;”而不是“数据;”?
  • @Silicomancer 只需 data; 产生编译器警告“语句无效”。
  • @Silicomancer 如果您忘记添加定义并且您并没有真正使用该对象,那么奇怪的是您不会出错。为了得到它,您必须使用具有一些副作用的对象。 Here is a demo 如何实际获取链接器错误。
  • @Silicomancer 实际上标准 (3.2/4) 表示,如果您没有使用 odr 的对象的定义,则不需要诊断。
猜你喜欢
  • 2011-01-14
  • 1970-01-01
  • 2017-07-01
  • 2016-01-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多