是否可以在C++标准库中实现always_false
Is it possible to implement always_false in the C++ standard library?
在某些情况下,如果尝试实例化某个模板,则使用always_false
帮助程序会导致无条件static_assert
失败:
template <class... T> struct always_false : std::false_type {};
template<class T>
struct UsingThisShouldBeAnError {
static_assert(always_false<T>::value, "You should not use this!");
};
这个助手是必要的,因为模板定义必须(至少在理论上)至少有一组模板参数,可以为其生成有效的专业化,以便程序形成良好的格式:
〔temp.res〕/8:程序格式错误,无需诊断,如果:
- 无法为模板生成有效的专门化[…],并且模板未实例化,或者
[…]
(因此,在上面写入static_assert(false, "You should not use this!");
将是格式错误的,编译器总是可以激发静态断言,即使没有实例化模板,这也不是目的。)
以下是涉及这种模式的问题的快速抽样(包括进一步的解释):
禁止使用"static_assert"的函数
如果成员模板不是';t实例化?
模板的条件编译
将always_false
作为标准库中的工具可能会很有用,这样我们就不必不断地重新编写它。然而,以下问题的答案让我怀疑这是否可能:
依赖的非类型参数包:标准怎么说?
这里提出了一个论点(也关于[temp.res]/8),即std::enable_if_t<T>
总是void
或不是类型,任何人进一步专门化它都是非法的。因此,一个模板依赖于理论上的";特殊性";为了避免[temp.res]/8子句,std::enable_if
实际上导致程序格式错误,不需要诊断。
回到我的问题:如果标准提供always_false
,它将不得不禁止图书馆用户像往常一样专门化它(原因很明显)。但根据上述推理,这将推翻always_false
的全部观点(即理论上它可以专门用于std::false_type
以外的东西)——关于[temp.res]/8,它将与直接使用std::false_type
相同。
我的推理错了吗或者标准库实际上不可能以有意义/有用的方式(在没有核心语言更改的情况下)提供always_false
?
在C++20中,使用lambda,您可以执行以下操作:
template <class... T> struct always_false : std::false_type {};
// To have true, but for a type that user code can't reuse as lambda types are unique.
template <> struct always_false<decltype([](){})> : std::true_type{};
经过反思,我认为这是不可能的:封闭模板可能有其他特殊化的假设类型应该满足的限制:
对于static_assert(is_enum_v<T> && always_false_v<T>)
,该类型应该是枚举。
更受约束的是,对于static_assert(is_same_v<T, int> && always_false_v<T>)
,它适用于int
。
编辑:C++23现在允许在非实例化部分中使用static_assert(false);
:)
套用Jarod的想法,它可能是类似的东西
template <class... T> struct always_false : std::false_type {};
template <> struct always_false</* implementation defined */> : std::true_type{};
其中/* implementation defined */
可以由std::_ReservedIdentifer
填充。用户代码无法访问它,因为标识符是为库保留的,但存在一个特殊化true
。这应该可以避免关于ODR和专业化中的lambdas的问题。
所有这样的尝试都会导致程序格式错误,不需要诊断。
阻止您使用static_assert(false)
的子句会使您的程序格式不正确,不需要基于实际实例化的实际可能性进行诊断,而不是基于编译器是否能够解决。
这些技巧只会使编译器更难检测到程序格式错误的事实。他们发布的诊断不是必需的,您绕过发布的诊断的能力只意味着您使编译器生成了一个格式错误的程序,而标准对其行为没有任何限制。
(写入static_assert(false,"你不应该使用这个!");因此,上面的格式不正确,编译器可能总是触发静态断言,即使没有实例化模板,这也不是目的。)
完全相同的结论适用于您的
template <class... T> struct always_false : std::false_type {};
template<class T>
struct UsingThisShouldBeAnError {
static_assert(always_false<T>::value, "You should not use this!");
};
我声称在上述程序中没有UsingThisShouldBeAnError
的有效实例化。
http://eel.is/c++吃水深度/温度res#6.1
程序格式错误,不需要诊断,如果:(6.1)不能为模板[…]"生成有效的专门化;
无法为此模板生成有效的专用化。
要避免此陷阱,您的程序必须具有
template <> struct always_false<SomeListOfTypes> : std::true_type {};
如果在标准中指定了一个always_false
,但不能发生这种情况,那么使用标准中的always_false
对您没有任何帮助。因为该标准要求专业化";可以生成";。
如果实例化模板的唯一方法是在一个格式错误的程序中,那么这对单词"来说是一个巨大的扩展;可以";。因此,在true_type
专业化中使用不允许使用的保留类型或魔术类型是不合理的。
退而求其次;格式错误,ndr";这是因为标准编写者希望允许对损坏的代码进行诊断,但不想强制执行。检测这种损坏的代码通常是一个很难解决的问题,但可以检测到简单的情况。围绕代码未被破坏的假设进行优化是有用的。
所有注入static_assert(false, "message")
的尝试都是围绕着C++代码有效的意图进行的。
我们有一个函数的构造,对它来说,成功查找是语言中已经存在的错误。
template<class T>
void should_never_be_found(tag<T>) = delete;
当然,漏洞在于这里缺乏诊断信息。
template<class T>
void should_never_be_found(tag<T>) = delete("Provide an custom ADL overload!");
此外,无法对=delete
模板进行专门化。
您似乎想要的是:
template<class T>
struct UsingThisShouldBeAnError = delete("You should not use this");
这是直接的、有意的,并且与其他=delete
病例的工作方式一致。
CCD_ 28旁路需要魔术;欺骗;编译器绕过标准中明确编写的部分,以阻止你做你想做的事情。
该语言中缺少模板类上的=delete("string")
和=delete
语法。
只需使用选项-fdelayed-template-parsing
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- std::random_device是如何实现的