强制初始化模板类的静态数据成员 [英] Forcing initialization of static data member of template class

查看:193
本文介绍了强制初始化模板类的静态数据成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于未初始化的模板类的静态数据成员,存在一些问题。很遗憾,这些都没有能够帮助我处理具体问题的答案。

There have been a few questions about static data members of template classes not being initialized. Unfortunately none of these had answers that were able to help me with my specific problem.

我有一个模板类,它有一个静态数据成员,类型(即,必须是专门的)。如果不是这样,使用不同的模板函数应该会导致链接器错误。

I have a template class that has a static data member that must be instantiated explicitly for specific types (i.e., must be specialized). If this is not the case, using a different template function should cause a linker error.

以下是一些代码:

#include <iostream>

template <typename T>
class Instantiate {
public:
    static Instantiate instance;
private:
    Instantiate(std::string const &id) {
        std::cout << "Instantiated " << id << "." << std::endl;
        // Additional, important side effects...
    }
};

template <typename T>
void runme() {
    // Do something to ensure instance is instantiated,
    // without creating run-time overhead.
    // The following only works without optimization.
    void *force = &Instantiate<T>::instance;
}

// Instances need to be explicitly specialized for specific types.
template <> Instantiate<int> Instantiate<int>::instance = {"int"};

int main() {
    // This is OK, since Instantiate<int>::instance was defined.
    runme<int>();
    // This should cause a (linker) error, since
    // Instantiate<double>::instance is not defined.
    runme<double>();
}

调用 runme< T> 应该要求定义实例化< T> :: instance ,而不实际使用它。获取指向实例的指针如下所示 - 但前提是没有启用优化。我需要一个不同的方法,至少工作 O2 ,并且如果实例化实例发生在不同的编译单元。

Calling runme<T> should require that Instantiate<T>::instance is defined, without actually using it. Getting a pointer to instance as shown works - but only if no optimizations are enabled. I need a different method that works with at least O2, and also works if the instantiation of instance occurs in a different compilation unit.

问题:
如何确保在调用 runme 类型 T 没有明确的实例化< T> :: instance >

Question: How can I ensure that I get a linker error when calling runme with a type T for which no explicit Instantiate<T>::instance has been defined/specialized?

推荐答案

如果我正确理解你的文章,你的示例代码可以简化为:

If I understand your post correctly, your sample code can be reduced to:

struct X
{
    static int x;
};

int main()
{
    void *f = &X::x;
}

,并且您发现只有 -O2 未通过。

and you are finding that a link error is only generated if -O2 is not passed.

单一定义规则非常复杂,相当确信& X :: x 被视为 odr-use 。但是,[basic.def.odr] / 4说:

The One Definition Rule is extremely complicated but I'm fairly confident that &X::x counts as odr-use. However , [basic.def.odr]/4 says:


每个程序都必须包含每个非内联函数或变量在该程序中使用的;无需诊断。

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

最后3个字是编译器的一个大的逗号子句,它基本上允许你看到的行为。程序是错误的(因此任何可执行文件生成的都有完全未定义的行为),但标准不要求编译器/链接器产生任何警告或错误。

The last 3 words is a big weasel clause for compilers, it basically permits the behaviour that you are seeing. The program is ill-formed (and so any executable generated has completely undefined behaviour) but the standard does not require that the compiler/linker produce any warnings or errors.

如果ODR规则没有这个转义子句,那么优化器的工作将会更加困难;例如它可以确定您的函数只包含死代码,但它必须有额外的逻辑来检查所有 odr使用的功能。

If the ODR rule didn't have this escape clause then the optimizer's job would be much more difficult; e.g. it could have identified that your function only contains dead code but it would have to have extra logic to check for all odr-use of things in the function.

那么我们如何解决这个问题呢?由于变量的所有ODR违例具有相同的无诊断需求条款,因此没有可靠的解决方案。我们将不得不尝试找到你的特定编译器喜欢的东西,或者一种阻止优化的方法。

So how do we fix this? Since all ODR violations for variables have the same "no diagnostic required" provision, there's no guaranteed solution. We will have to try and find something that your particular compiler likes, or a way to prevent optimization.

这对我有用gcc 4.8.1:

This worked for me with gcc 4.8.1:

void *volatile f = &X::x;

(同样的事情在你的代码示例中工作)。这将导致一个小的运行时代码尽管(编译器必须生成一个指令调用 runme )。也许别人会想出一个更好的技巧:)

(and the same thing worked in your code sample). This will incur a small runtime penalty though (the compiler has to generate an instruction for the call to runme). Maybe someone else will come up with a nicer trick :)

这篇关于强制初始化模板类的静态数据成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆