【问题标题】:C++ templated static member constructor not being called未调用 C++ 模板静态成员构造函数
【发布时间】:2014-02-20 07:09:52
【问题描述】:

我有两个具有静态成员实例的类的测试用例。第一个使用非模板样本,而第二个依赖于通用对象类型。

困境很简单:静态成员的构造函数在主函数之前被调用(应该如此),但只针对特定的对象类型。泛型类型不表现出相同的行为。事实上,构造函数根本没有被编译。似乎编译器决定完全忽略它作为(不完全合理的)优化的一种手段。

我想知道发生了什么,以及可以做些什么来使它以最优雅的方式工作。我认为显而易见的答案是:在代码的某处使用该静态成员。我不想这样做,因为特定类型的情况在不使用该静态成员的情况下工作,除了在其构造函数中执行一些“工作”。

代码示例:

//////////////////////////////////////////////
// Specific case
//////////////////////////////////////////////
class CPassive
{
public:
    CPassive()
    {
        printf(" passively called ");
    }
};

class CActive
{
private:
    static CPassive ms_passive;
};
CPassive CActive::ms_passive;
///////////////////////////////////////////////////////////
// GENERIC TYPES
///////////////////////////////////////////////////////////
class CSample
{
public:
    CSample()
    {
        printf("sample ");
    }
};

template <typename T>
class CGenericPassive
{
public:
    CGenericPassive()
    {
        T sample;
        printf(" generic passive .. ");
    }
private:
};

template <typename T>
class CGenericActive
{
private:
    static CGenericPassive<T> ms_passive;
};
template<typename T>
CGenericPassive<T> CGenericActive<T>::ms_passive;

int main(int argc, char** argv)
{
    CActive activeExample;// instantiates the static member
    CGenericActive<CSample> activeExample; // obliterates the static from the class def.
}

【问题讨论】:

  • 我想我还没有完全理解。对于泛型类型,您希望运行多少个版本的类,为什么您希望运行这些版本而不是无限数量?例如,CGenericPassive&lt;int&gt; CGenericActive&lt;int&gt;::ms_passive;CGenericPassive&lt;char***&gt; CGenericActive&lt;char***&gt;::ms_passive; 您所说的“从类中消除静态”是什么意思?
  • 有什么问题?这段代码没有按照你的想法做吗?这个代码输出什么?更具体地说,这段代码在做什么,你需要调整你的教育?
  • @Dan 模板化的静态成员必须在非模板化函数中显式引用才能被实例化,而普通静态不会。我得到了一个答案,指出了这一点,但感觉很老套,或者好像 c++ 的规则中有一个怪癖。
  • 您还没有定义问题所在。有问题吗?为了记录,成员没有被实例化。班是。如果你不调用成员函数,那么就没有必要存在一个。如果您不专门化模板,则不需要存在该模板专门化。但是实例化代码必须在创建类实例时生成。
  • 我确实已经定义了问题是什么(但是问题很长并且充满了示例代码,因此乍一看可能很无聊和混乱)。简而言之:为什么只为非模板类​​创建/构造该静态成员,而不是为模板类创建/构造,即使创建了此容器类类型的对象?这个成员将被编译器丢弃并不是很明显(编译器遵循什么规则:丢弃非直接使用的模板代码?)。谢谢!

标签: c++ templates visual-c++ static generic-programming


【解决方案1】:

您希望实例化的每个类模板的每个(非虚拟)成员都需要直接或间接地从非模板代码中引用。实例化类本身是不够的。

这由标准 14.7.1/2 管理:

除非类模板或成员模板的成员已被显式实例化或显式特化,否则当在需要成员定义存在的上下文中引用特化时,会隐式实例化该成员的特化;特别是,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非该静态数据成员本身的使用方式要求该静态数据成员的定义存在。

在您的情况下,从 CGenericActive 构造函数中引用成员就足够了(显然您需要编写此构造函数),如下所示:

CGenericActive()
 {
   // just reference it so it gets instantiated
   (void)ms_passive;
 }

Full live example.

【讨论】:

  • 谢谢!这是我也尝试过的一种解决方法,但感觉很糟糕。我想我必须将更多逻辑委派给静态成员,以使其更透明、更可靠地运行,以免混淆第三方程序员。顺便说一句:是否有任何决定这种行为的 C++ 规则?与模板代码相同:如果没有在任何地方使用,它不会(显然)被生成和编译? (因为,直觉上看起来是这样,即使成员的类构造函数正在做一些不应该被优化掉的工作)。
  • 增加了对标准章节的引用。
猜你喜欢
  • 1970-01-01
  • 2013-01-16
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-10
  • 1970-01-01
相关资源
最近更新 更多