0

通常在编写模板代码时,我发现自己需要将模板类型的实例存储在成员变量中。例如,我可能需要缓存一个值以供以后使用。我希望能够将我的代码编写为:

struct Foo
{
    template<typename T>
    T member;
    
    template<typename T>
    void setMember(T value)
    {
        member<T> = value;
    }

    template<typename T>
    T getMember()
    {
        return member<T>;
    }
};

成员在使用时是专门的。我的问题:

  1. 当前的 C++ 生成编码工具是否可以使用这种模板化成员变量?
  2. 如果没有,是否有任何关于这种语言功能的建议?
  3. 如果没有,是否有任何技术原因导致这样的事情是不可能的?

很明显,我不想列出所有可能的类型(例如在 a 中std::variant),因为这不是生成式编程,并且如果库的用户与作者不同,则不可能。

编辑:我认为这在某种程度上回答了我上面的第三个问题。原因是今天的编译器无法将对象的实例化推迟到整个程序被解析之后: https ://stackoverflow.com/a/27709454/3847255

4

2 回答 2

1

这可以通过结合现有设施在图书馆中实现。

最简单的实现是

std::unordered_map<std::type_index, std::any>

这有点低效,因为它将每个std::type_index对象存储两次(一次在 key 中,一次在 each 中std::any),因此std::unordered_set<std::any>使用自定义透明散列和比较器会更有效;不过,这将是更多的工作。

例子

如您所说,图书馆的用户可能与作者不同;特别是, 的析构函数Foo不知道设置了哪些类型,但它必须定位这些对象并调用它们的析构函数,注意使用的类型集在 的实例之间可能不同Foo,因此这些信息必须存储在运行时容器中Foo.

如果您对std::type_indexand隐含的 RTTI 开销持谨慎态度std::any,我们可以将它们替换为较低级别的等效项。因为std::type_index您可以使用指向static标记变量模板实例化(或任何类似工具)的指针,并且std::any可以使用类型擦除std::unique_ptr<void, void(*)(void*)>,其中删除器是函数指针:

using ErasedPtr = std::unique_ptr<void, void(*)(void*)>;
std::unordered_map<void*, ErasedPtr> member;
struct tag {};
template<class T> inline static tag type_tag;

    member.insert_or_assign(&type_tag<T>, ErasedPtr{new T(value), [](void* p) {
        delete static_cast<T*>(p);
    }});

例子。请注意,一旦你创建std::unique_ptr了函数指针的删除器,它就不再是默认可构造的,所以我们不能再使用operator[]了,而必须使用insert_or_assignand find。(同样,我们遇到了相同的 DRY 违规/低效率,因为删除器可以用作映射的键​​;利用这一点留给读者练习。)

于 2021-01-15T23:51:03.610 回答
1

当前的 C++ 生成编码工具是否可以使用这种模板化成员变量?

不,不完全是你描述的。可以使封闭类成为模板并使用模板参数来描述类成员的类型。

template< typename T >
struct Foo
{
    T member;
    
    void setMember(T value)
    {
        member = value;
    }
    
    T getMember()
    {
        return member;
    }
};

在 C++14 及更高版本中,有变量 templates,但不能使模板成为类的非静态数据成员。

如果没有,是否有任何关于这种语言功能的建议?

从来没听说过。

如果没有,是否有任何技术原因导致这样的事情是不可能的?

主要原因是这将导致无法定义类的二进制表示。与模板相反,类是一种类型,这意味着它的表示必须是固定的,这意味着在程序中的任何地方都Foo必须Foo::member表示相同的东西——相同的类型、相同的对象大小和二进制布局等等。另一方面,模板不是类型(或者,在变量模板的情况下,不是对象)。它在实例化时变为一个,并且每个模板实例化都是一个单独的类型(在变量模板的情况下 - 对象)。

于 2021-01-15T23:56:41.527 回答