Как задержать создание экземпляра статического элемента данных в Visual C++?


Следующий код работает с GCC и Clang, но не с Visual C++:

#include <type_traits>

struct MyType {
    static constexpr std::size_t it = 10;
};

struct MyType2 {
};

template<typename T>
struct Type2 {
    static constexpr std::size_t it = T::it;
};

int main() {
    Type2<MyType> t1;
    Type2<MyType2> t2; // Visual C++ complains that MyType2::it doesn't exist
    (void) t1;
    (void) t2;
}

В соответствии с разделом 14.7.1 стандарта:

... инициализация (и любые связанные с ней побочные эффекты) статического объекта элемент данных не возникает, если статический элемент данных не является самим собой используется способом, требующим определения статического элемента данных существовать

Таким образом, кажется, что это ошибка в Visual C++; он должен принять это код.

Несмотря на это, я все еще хочу иметь возможность сделать это с помощью Visual C++. Как проще всего разрешить Visual C++ работать без изменения синтаксиса доступа к переменной-члену? Я также требую, чтобы Type2<T>::it не существовало, когда T::it не существует, или чтобы в противном случае можно было бы отделиться от существования Type2<T>::it.


Это меняет синтаксис, поэтому я не хочу этого:

template<typename T>
struct Type2 {
    template<typename = void>
    static constexpr std::size_t it = T::it;
};

// Type2<MyType>::it<>

Это большая работа, потому что мой класс будет содержать больше, чем простой constexpr переменная:

template<typename T, typename = void>
struct Type2 {
};

template<typename T>
struct Type2<T, decltype((void) T::it)> {
    static constexpr std::size_t it = T::it;
};
1 8

1 ответ:

Вы можете наследовать it (когда он существует) вместо того, чтобы объявлять его напрямую:

template<typename T, typename = void>
struct ItHolder
{};

template<typename T>
struct ItHolder<T, decltype((void) T::it)> {
    static constexpr std::size_t it = T::it;
};


template<typename T>
struct Type2 : ItHolder<T> {
};
Другими словами, просто возьмите то, что вы уже предложили, и объедините это, используя другой слой косвенности.