【问题标题】:Force template static member instantiation强制模板静态成员实例化
【发布时间】:2017-10-03 14:18:53
【问题描述】:

我正在尝试创建仅在模板被实例化时才执行某些代码的程序(它将用于低级驱动程序初始化)。 现在我有以下解决方案。

class Initializer
{
public:
    Initializer(){
        // This code is executed once
    }

    void silly() const{

    }
};

template <class T>
class Proxy{
protected:
    static const Initializer init;
};

template<class T>
const Initializer Proxy<T>::init;

template<class T>
class MyTemplate : public Proxy<void>{
public:
    static void myMethod1(){
        init.silly();

        // ... Something useful
    }

    static void myMethod2(){
        init.silly();

        // ... Something useful
    }
};

Initializer 默认构造函数仅在我在某处调用myMethod1()myMethod2() 时执行。

但是有没有办法摆脱那些init.silly(); 行?

【问题讨论】:

  • “强制实例化:”和“检查实例化”是两个完全不同的东西。
  • 是否要为Proxy 的每个实例创建Initializer?例如。如果您创建Proxy&lt;void&gt;Proxy&lt;char&gt; 那么Initializer 将被构造两次?
  • 不,我只想创建一个Initializer 实例。我将永远继承自Proxy&lt;void&gt;

标签: c++ templates static instantiation


【解决方案1】:

您的问题是,模板的成员除非被引用,否则不会被实例化。

您可以直接引用成员,而不是调用init.silly()

    static void myMethod1(){
        (void)init;

        // ... Something useful
    }

或者,如果您希望绝对始终定义 init,您可以显式实例化它:

template<>
const Initializer Proxy<void>::init{};

【讨论】:

  • 这样更好,但仍然需要多行代码。如果我使用init 的显式实例化,即使MyTemplate 没有被实例化,它的构造函数也会被执行。事实并非如此。
【解决方案2】:

模板和低级驱动程序初始化?.. 我会尽量使它成为 C :) 以确保准确的行为。

也许你可以这样做:

class Initializer
{
public:
    Initializer() {
        // This code is executed once
    }
};

template <class T>
class Proxy {
protected:
    Proxy()
    {
        static Initializer init;
    }
};

template<class T>
class MyTemplate : public Proxy<void> {
public:
    void myMethod1() {
        // ... Something useful
    }

    void myMethod2() {
        // ... Something useful
    }
};

您的所有代码都只使用静态函数,并没有真正说明您为什么要使用类和模板。通过我的更改,我将myMethod1myMethod2 设为非静态,Proxy() 构造函数将创建一次Initializer

请注意,由于所有这些模板混乱,您的Initializer 可能会在您实例化代理模板时执行多次。你真的是这个意思吗?如果没有,请转换为没有此意外结果的清晰可读代码。这也将对其他人更好地维护和阅读:

class Initializer
{
    Initializer() {
        // This code is executed once
    }
public:
    void init()
    {
        static Initializer init;
    }
};


template<class T>
class MyTemplate {
public:
    static void myMethod1() {
        Initializer::init();
        // ... Something useful
    }

    static void myMethod2() {
        Initializer::init();
        // ... Something useful
    }
};

这清楚地表明Initializer 只会在调用myMethod1myMethod2 之前创建一次。如果没有人调用您的Initializer::init,则应在链接时删除来自Initializer 的代码。

【讨论】:

  • 哦,是的!这样干净多了。它还不必担心模板成员何时被实例化的详细问题——这只是标准的那种黑暗角落,a)开发人员会感到困惑; b) compiler 开发人员偶尔会感到困惑。
猜你喜欢
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多