【发布时间】:2019-05-03 07:04:43
【问题描述】:
我的 Instance 类存在一个问题,我注意到两种初始化静态成员的方法导致的行为差异。
类模板 Instance 正在跟踪唯一计数。唯一计数用于跟踪特定类型的派生类的数量。它还用于为派生类分配唯一的 ID/索引。
第一个初始化如下:
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_static_assign{ std::numeric_limits<Key>::min() };
第二个是这样初始化的:
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_default{ 0 };
程序的输出
1 1
2 1
我希望这两个值相等,因为它们都应该递增。但是 count_static_assign 给出了错误的输出,因为它似乎重置并等于 1 两次。因此,我想知道为什么这两个静态变量的行为会有所不同。
这是演示错误的程序的文件。
实例.h
#ifndef INSTANCE_H
#define INSTANCE_H
#include <cinttypes>
#include <limits>
#include <iostream>
template<typename Derived, typename Key = std::uint16_t>
class Instance {
public:
using KeyType = Key;
static KeyType count_static_assign;
static KeyType count_default;
public:
Instance() = default;
virtual ~Instance() = default;
virtual KeyType getInstance() const = 0;
protected:
static KeyType generate() {
count_static_assign++;
count_default++;
std::cout << count_default << ' ' << count_static_assign << '\n';
return count_default;
}
};
//doesn't behave as expected
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_static_assign{ std::numeric_limits<Key>::min() };
//behaves as expected
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_default{ 0 };
#endif
Base.h
#ifndef BASE_H
#define BASE_H
#include <cinttypes>
#include <typeindex>
#include <memory>
#include "Instance.h"
class Base : public Instance<Base>
{
public:
Base(){}
~Base(){}
};
template<typename Derived>
class CRTPBase : public Base {
public:
static const KeyType STATIC_TYPE;
CRTPBase() {}
virtual ~CRTPBase() {}
virtual KeyType getInstance() const override {
return STATIC_TYPE;
}
};
template<typename Derived>
const typename CRTPBase<Derived>::KeyType CRTPBase<Derived>::STATIC_TYPE = CRTPBase<Derived>::generate();
#endif
Foo.h
#ifndef FOO_H
#define FOO_H
#include "Base.h"
struct Foo : public CRTPBase<Foo> {
Foo();
~Foo();
};
#endif
Foo.cpp
#include "Foo.h"
Foo::Foo()
{
}
Foo::~Foo()
{
}
Bar.h
#ifndef BAR_H
#define BAR_H
#include "Base.h"
struct Bar : public CRTPBase<Bar>
{
public:
Bar();
~Bar();
};
#endif
Bar.cpp
#include "Bar.h"
Bar::Bar()
{
}
Bar::~Bar()
{
}
main.cpp
#include "Foo.h"
#include "Bar.h"
int main() {
Foo foo;
Bar bar;
std::cin.get();
}
如果重要的话,我使用 Visual Studio 2017(Full Version-191426433) 编译。此外,调试和发布模式没有区别。
【问题讨论】:
-
如果有关系,我正在使用 Visual Studio 编译 -- 你使用的是什么版本的编译器?
-
添加了来自 _MSC_FULL_VER 的编译器版本号值
-
不,只提Visual Studio 2010、2013、2015等
-
明白了,把版本加在最后了。
-
好的。你知道跨模块的静态初始化顺序没有定义吗?将所有这些代码粘贴到一个源文件中并进行测试。你得到不同的结果吗?
标签: c++ class templates static initialization