在编写模板化代码时,我经常发现自己需要在成员变量中存储模板类型的实例。例如,我可能需要缓存一个值,以便稍后使用。我希望能够将我的代码写成:
struct Foo
{
template
T member;
template
void setMember(T value)
{
member = value;
}
template
T getMember()
{
return member;
}
};
其中成员在使用时是专门化的。我的问题是:
这种模板化的成员变量在当前的C++生成编码工具中是可能的吗?
如果没有,有没有关于这种语言特性的建议?
如果没有,有没有技术上的原因导致这种情况不可能发生?
很明显,我不想列出所有可能的类型(例如,在std::variant),因为这不是生成式编程,如果库的用户与作者不同,则不可能实现。
编辑:我认为这在某种程度上回答了我上面的第三个问题。原因是今天的编译器不能将对象的实例化推迟到整个程序解析之后:
https://stackoverflow.com/a/27709454/3847255
发布于 2021-01-16 07:51:04
通过组合现有的设施,这在库中是可能的。
最简单的实现是
std::unordered_map
这有点低效,因为它将每个 std::type_index 对象存储两次(一次在键中,一次在每个 std::any 中),因此具有自定义透明哈希和比较器的 std::unordered_set 会更有效;不过,这将是更多的工作。
正如你所说,图书馆的用户可能与作者不一样;特别是 Foo 的析构函数不知道设置了哪些类型,但它必须定位那些对象并调用它们的析构函数,注意 Foo 实例之间使用的类型集可能不同,因此这些信息必须存储在运行时Foo 中的容器。如果您对 std::type_index 和 std::any 隐含的 RTTI 开销持谨慎态度,我们可以将它们替换为较低级别的等效项。对于 std::type_index ,您可以使用指向静态标签变量模板实例化(或任何类似工具)的指针,对于 std::any 您可以使用类型擦除的 std::unique_ptr ,其中删除器是函数指针
using ErasedPtr = std::unique_ptr;
std::unordered_map member;
struct tag {};
template inline static tag type_tag;
member.insert_or_assign(&type_tag, ErasedPtr{new T(value), [](void* p) {
delete static_cast(p);
}});
请注意,一旦将 std::unique_ptr 的删除器设为函数指针,它就不再是默认可构造的,因此我们不能再使用 operator[] 而必须使用 insert_or_assign 和 find。(同样,我们有同样的 DRY 违规/低效率,因为删除器可以用作映射的键;利用这一点留给读者作为练习。)
发布于 2021-01-16 07:56:42
这种模板化的成员变量在当前的C++生成编码工具中是可能的吗?
不,不完全是你所描述的。可以将封闭的类作为模板,并使用模板参数来描述类成员的类型。
template< typename T >
struct Foo
{
T member;
void setMember(T value)
{
member = value;
}
T getMember()
{
return member;
}
};
在C++14和更高版本中,有
可变模板
,但不能使模板成为类的非静态数据成员。
如果没有,有没有关于这种语言特性的建议?
据我所知没有。
如果没有,有没有技术上的原因导致这种情况不可能发生?
主要原因是,这将使定义类的二进制表示变得不可能。与模板相反,类是一种类型,这意味着它的表示必须是固定的,这意味着在程序中的任何位置Foo和Foo::member必须意味着相同的东西-相同的类型,相同的对象大小和二进制布局,等等。另一方面,模板不是类型(或者,在可变模板的情况下,不是对象)。当它成为一体时,它就变成了一个整体。
实例化
,并且每个模板实例化都是一个单独的类型(在可变模板-对象的情况下)。
https://stackoverflow.com/questions/65744963
复制相似问题