Các mã sau đây làm việc với GCC và Clang, nhưng không phải với Visual C++:Làm cách nào để trì hoãn việc khởi tạo thành viên dữ liệu tĩnh trong 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;
}
Theo phần 14.7.1 của tiêu chuẩn:
... việc khởi tạo (và bất kỳ bên liên quan -effects) của một thành viên dữ liệu tĩnh không xảy ra trừ khi các thành viên dữ liệu tĩnh là chính nó sử dụng theo cách mà đòi hỏi định nghĩa của các thành viên dữ liệu tĩnh tồn tại
Vì vậy, có vẻ như đây là một lỗi trong Visual C++; nó phải chấp nhận mã này.
Bất kể, tôi vẫn muốn có thể thực hiện việc này bằng Visual C++. Cách dễ nhất để cho phép Visual C++ hoạt động, mà không thay đổi cú pháp truy cập biến thành viên là gì? Tôi cũng yêu cầu rằng Type2<T>::it
không tồn tại khi T::it
không tồn tại hoặc có thể SFINAE không tồn tại trong số Type2<T>::it
.
này thay đổi cú pháp, vì vậy tôi không muốn nó:
template<typename T>
struct Type2 {
template<typename = void>
static constexpr std::size_t it = T::it;
};
// Type2<MyType>::it<>
Đây là rất nhiều công việc, bởi vì lớp học của tôi sẽ chứa nhiều hơn một constexpr
biến đơn giản:
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;
};
Điều này dường như hoạt động: http://coliru.stacked-crooked.com/a/1fd7999053358d43 –
Bạn đang đọc quá nhiều vào tiêu chuẩn. Nó không nói rằng khởi tạo không hợp lệ được cho phép nếu thành viên không bao giờ được sử dụng. Ví dụ. 'it = (abort(), 0)' khác với ví dụ của bạn vì nó tạo ra lỗi thời gian chạy và không phải là lỗi biên dịch. –