C++ 静态类模板成员:无效的应用程序‘;尺寸’;不完整类型
下面是我试图创建的池对象的一个最小工作示例(显然不是功能完整的-我只是想说明我遇到的问题) 我有一个类模板C++ 静态类模板成员:无效的应用程序‘;尺寸’;不完整类型,c++,templates,C++,Templates,下面是我试图创建的池对象的一个最小工作示例(显然不是功能完整的-我只是想说明我遇到的问题) 我有一个类模板存储,它包含对齐的存储: template<typename T, std::size_t N> struct Storage { std::aligned_storage_t<sizeof(T), alignof(T)> data[N]; }; 现在,我有了一个从PoolObj继承的类,它有一个静态存储成员池,因此当我使用new创建实例时,我将从池中获得存
存储
,它包含对齐的存储
:
template<typename T, std::size_t N>
struct Storage
{
std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
};
现在,我有了一个从PoolObj
继承的类,它有一个静态存储成员池
,因此当我使用new
创建实例时,我将从池中获得存储
struct Foo : PoolObj<Foo>
{
static Storage<Foo, 10> pool;
};
Storage<Foo, 10> Foo::pool {};
但是,现在我正在尝试启用PoolObj
类模板:
template<typename T>
struct Bar : PoolObj<Bar<T>>
{
static Storage<Bar<T>, 10> pool;
};
template<typename T>
Storage<Bar<T>, 10> Bar<T>::pool {};
编辑:
有趣的是
- 哪个编译器是正确的
- 这是gcc中的错误吗
第二次编辑:
根据评论,它也适用于VS2017。因此,我想我倾向于gcc中的一个bug
哪个编译器是正确的
一般来说,相关的措辞应该是
[temp.inst-2]类模板专门化的隐式实例化会导致声明的隐式实例化,而不是类成员函数、成员类、作用域成员枚举、静态数据成员的定义、默认参数或noexcept说明符的隐式实例化,成员模板和朋友
及
[temp.inst-3]除非类模板或成员模板的成员已显式实例化或显式专用化,当在要求成员定义存在的上下文中引用专门化时,或者如果成员定义的存在影响程序的语义,则隐式实例化成员的专门化;特别是,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非静态数据成员本身的使用方式要求静态数据成员的定义存在
静态成员变量是一个声明,而不是一个定义,因此clang是正确的
也就是说,这两个编译器在决定什么是“实例化声明而不是定义”和“需要成员定义存在的上下文,或者成员定义的存在是否会影响程序的语义”时都表现得很疯狂(你可以在这里找到很多类似于最近的情况)
作为一种解决方法,您可以使用静态引用
template<typename T>
struct Bar : PoolObj<Bar<T>>
{
static Storage<Bar<T>, 10>&& pool;
};
template<typename T>
Storage<Bar<T>, 10>&& Bar<T>::pool = Storage<Bar<T>, 10>{}; // note, the temporary is lifetime-extended here
模板
结构栏:PoolObj
{
静态存储和池;
};
模板
存储&&Bar::池=存储{};//注意,这里的临时生命周期是延长的
这似乎说服了clang和gcc避免实例化对齐的存储(应该是这样)。我想这是因为您将Bar用作类Bar定义的一部分。不太确定,不足以作为正式答复。但是这个错误是有道理的。再加上一点,如果编译器在定义Bar
期间试图理解静态成员池的大小,那么此时Bar
是不完整的。当它检查std::aligned_storage\u t
以了解池的大小时,Bar
(在本上下文中为t)仍然不完整,并且对不完整类型获取大小是非法的。@OriBSstorage
仅在声明Bar
时为Bar
实例化。在它被实例化的时候,它肯定有完整的类型?此外,它在叮当声下工作-哪个编译器是正确的?@OriBS:我在这里不明白为什么只有模板case的类型才是不完整的。顺便说一句,您的示例也可以用visual studio 2017编译
$ ./a.out
new T
delete T
template<typename T>
struct Bar : PoolObj<Bar<T>>
{
static Storage<Bar<T>, 10> pool;
};
template<typename T>
Storage<Bar<T>, 10> Bar<T>::pool {};
int main()
{
Bar<int>* b = new Bar<int>();
delete b;
return 0;
}
In instantiation of ‘struct Storage<Bar<int>, 10ul>’:
required from ‘struct Bar<int>’
error: invalid application of ‘sizeof’ to incomplete type ‘Bar<int>’
std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
#include <type_traits>
#include <cstddef>
template<typename T, std::size_t N>
struct Storage
{
std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
};
template<typename T>
struct PoolObj
{
static void* operator new(std::size_t size)
{
return &T::pool.data[0];
}
static void operator delete(void* p, std::size_t size)
{
}
};
struct Foo : PoolObj<Foo>
{
static Storage<Foo, 10> pool;
};
Storage<Foo, 10> Foo::pool {};
template<typename T>
struct Bar : PoolObj<Bar<T>>
{
static Storage<Bar<T>, 10> pool;
};
template<typename T>
Storage<Bar<T>, 10> Bar<T>::pool {};
int main()
{
Foo* f = new Foo();
delete f;
Bar<int>* b = new Bar<int>();
delete b;
return 0;
}
template<typename T>
struct Bar : PoolObj<Bar<T>>
{
static Storage<Bar<T>, 10>&& pool;
};
template<typename T>
Storage<Bar<T>, 10>&& Bar<T>::pool = Storage<Bar<T>, 10>{}; // note, the temporary is lifetime-extended here