检测类型是否是主模板的专业化或用户提供的专业化

Nic*_*las 7 c++ c++20

假设我有这个:

template<typename T>
class my_template {...};
Run Code Online (Sandbox Code Playgroud)

现在,用户应该能够专门my_template针对自己的类型。他们会将这些类型传递给我的一些 API 函数,这些函数将使用 的属性my_template<T>来执行操作。

所以在我的代码中的某个时刻,我有一个my_template<T>. 我想要某种元函数,它接受my_template<T>并产生编译时值,true如果my_template<T>是用户提供的专业化(部分或显式),false如果不是。

最明显的解决方案是将私有成员别名或其他一些concept可检测的私有声明推入主要my_template定义中,并依赖于用户提供的专业化中不存在的情况。然而,用户可以通过提供适当的定义来建立明确的专业化。所以这并不是万无一失的。

这个问题并不是诡辩。C++20 规范有一个元函数ITER_CONCEPT(I),它根据是std::iterator_traits<I>来自主模板还是用户提供的专门化而具有不同的内部行为。当然,作为标准库,他们可以创建一个以 为前缀的标识符__作为主模板的成员,从而将任何来自用户空间的尝试伪造行为声明为未定义的行为。

这是只有编译器/标准库实现才能做到万无一失的事情,还是可以在 C++20 中做到这一点?

Bar*_*rry 10

最明显的解决方案是将私有成员别名或其他一些概念可检测的私有声明推入主 my_template 定义中,并依赖于用户提供的专业化中不存在的情况。然而,用户可以通过提供适当的定义来建立明确的专业化。所以这并不是万无一失的。

基本上就是这样,是的。例如,libstdc++ 的迭代器特征使其主类模板继承自隐藏的基类模板,然后检查是否从该基类模板继承。

是的,用户可以通过提供适当的定义来建立明确的专业化 - 但是,就像,不要这样做。这不是你偶然会做的事情,这是明显且毫无意义的恶意,典型的说法是图书馆和语言防御的是墨菲,而不是马基雅维利。

使用模块,您可以通过导出主模板但实际上不导出用于检查类模板是否专用的基类来使用户更难明显恶意:

export module std;

namespace std {
    template <typename T> struct __iterator_traits { };

    template <typename T>
    export struct iterator_traits : __iterator_traits { };
}
Run Code Online (Sandbox Code Playgroud)

现在用户甚至无法命名std::__iterator_traits来破坏库。也许反思仍然会给他们一种方法来做到这一点(假设这些东西仍然可以访问),但现在他们真的会经历很多困难。


说到反射,当前指定的 API ( P1240 ) 的一部分包括函数is_specializationis_partial_specializationis_explicit_specialization。如果这些意味着我认为他们的意思,那么当我们最终得到反思时,那么库就不会使用这些魔法基础/魔法成员黑客,而可以直接检查所提供的专业化是否是部分或显式专业化或不是。is_primary_specialization我认为为了完整性,图书馆可能应该添加。