静态类模板成员:将"sizeof"应用于不完整类型无效
static class template member: invalid application of ‘sizeof’ to incomplete type
这是我尝试创建的池化对象的最小工作示例(显然功能不完整 - 我只是想说明我遇到的问题)
我有一个类模板Storage
其中包含aligned_storage
:
template<typename T, std::size_t N>
struct Storage
{
std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
};
然后我有一个基类模板PoolObj
它使用operator new
从模板参数T
的静态类成员中分配出来:
template<typename T>
struct PoolObj
{
static void* operator new(std::size_t size)
{
std::cout << "new Tn";
return &T::pool.data[0];
}
static void operator delete(void* p, std::size_t size)
{
std::cout << "delete Tn";
}
};
现在我有一个继承自PoolObj
的类,并且有一个静态Storage
成员pool
,所以当我使用new
创建实例时,我将从池中获取存储。
struct Foo : PoolObj<Foo>
{
static Storage<Foo, 10> pool;
};
Storage<Foo, 10> Foo::pool {};
这一切都工作正常:
int main()
{
Foo* f = new Foo();
delete f;
return 0;
}
$ ./a.out new T delete T
但是,现在,我现在正在尝试制作一个启用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 {};
这不起作用
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];
- 为什么
T
对Foo
来说是Storage
完整的,而对Bar<int>
等人来说是不完整的? - 是否有可能实现我在这里希望的设计?
完整示例如下:(和大肠杆菌)
#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;
}
编辑:
有趣的是,这在叮当(coliru)中工作正常。
- 哪个编译器是正确的?
- 这是 gcc 中的错误吗?
第2次编辑:
根据评论,它在VS2017中也可以找到。因此,我想我倾向于 gcc 中的错误?
哪个编译器是正确的?
一般而言,相关措辞应为
[temp.inst-2]类模板专用化的隐式实例化会导致声明的隐式实例化,但不会导致类成员函数、成员类、作用域成员枚举、静态数据成员、成员模板和友元的定义、默认参数或 noexcept-specifier 的隐式实例化
和
[temp.inst-3]除非类模板或成员模板的成员已被显式实例化或显式专用化,否则当在需要成员定义的上下文中引用专用化时,或者如果成员定义的存在影响程序的语义,则隐式实例化成员的专用化;特别是, 静态数据成员的初始化(以及任何关联的副作用)不会发生,除非静态数据成员本身的使用方式要求存在静态数据成员的定义。
静态成员变量是一个声明,而不是一个定义,所以 clang 是对的。
也就是说,在决定">实例化声明而不是定义"和"需要成员定义的上下文或成员定义的存在是否影响程序的语义"是什么意思时,两个编译器的行为都很疯狂(你可以在SO上找到很多极端情况,就像最近这样)。
作为一种解决方法,您可以改用静态引用
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
这似乎说服了Clang和GCC避免实例化aligned_storage(因为它应该是)。
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 模板元程序查找相似的连续类型名称
- 是否可以从int转换为enum类类型
- 构造函数正在调用一个使用当前类类型的函数
- 我应该使用什么来代替void作为变体中的替代类型之一
- 类中的字符串不命名类型