我的 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 两次。因此,我想知道为什么这两个静态变量之间的行为有所不同。
这是该程序的文件,用于演示错误。
Instance.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(完整版- 191426433 )进行编译。此外,调试和发布模式没有什么区别。
答案 0 :(得分:1)
此代码对我来说似乎是正确的:count_default
和count_static_assign
具有常量表达式作为初始值设定项,因此必须在进行任何动态初始化之前对其进行初始化。 STATIC_TYPE
是动态初始化。
OP报告说,将std::numeric_limits<Key>::min()
更改为0
可以修复程序的行为,因此我推测编译器存在一个错误,它不考虑constexpr
函数{{1 }}为常量表达式。
要解决此问题,您可以尝试其他方法为std::numeric_limits<Key>::min()
提出一个常量初始化程序,例如您自己编写的constexpr函数,或您使用的每种类型的专门化。