Статический элемент шаблона класса, инициализированный дважды - PullRequest
0 голосов
/ 01 декабря 2018

В моем классе Instance существует проблема, заключающаяся в том, что я заметил разницу в поведении, связанную с двумя методами инициализации статического члена.

Шаблон класса Instance отслеживает уникальный счет.Уникальный счет используется для отслеживания количества производных классов для определенного типа.Он также используется для назначения уникального идентификатора / индекса для производных классов.

Первый инициализируется следующим образом:

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 )Скомпилировать.Кроме того, режим отладки и выпуска не имеет значения.

1 Ответ

0 голосов
/ 02 декабря 2018

Этот код мне кажется правильным: count_default и count_static_assign имеют константные выражения в качестве инициализаторов, поэтому они должны быть инициализированы перед любой динамической инициализацией.STATIC_TYPE - это динамическая инициализация.

OP сообщает, что изменение std::numeric_limits<Key>::min() на 0 исправляет поведение программы, поэтому я могу предположить, что у компилятора есть ошибка, которая не учитывает constexprфункция std::numeric_limits<Key>::min() является постоянным выражением.


Чтобы обойти это, вы можете попробовать другой способ создания постоянного инициализатора для count_static_assign, например, функцию constexpr, которую вы пишете сами, или специализацию для каждого типа, который вы используете..

...