如何通过自定义错误消息使概念失败 (C++20) [英] How to make a concept fail with a custom error message (C++20)

查看:44
本文介绍了如何通过自定义错误消息使概念失败 (C++20)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

概念非常适合将错误定位到不满足约束"的代码行.

但是,我想知道是否可以在那里发布自定义信息消息.static_assert 的好处就是这种可能性.用例:任何想要帮助用户找出某个表达式不满足约束的原因的库.

这里是一个简单的例子,只是为了有一些代码.您可能会争辩说,任何体面的用户"都必须能够找出编译器的注释"因为 'is_base_of<Base, C>'评估为假,但更多的自定义信息不会受到伤害.肯定会有更复杂的概念.

<预><代码>template概念 is_base_of = std::is_base_of_v<B, D>;模板<typename T, is_base_of<T>基本类型>struct BaseWrapper { };int main(){类基{};派生类:公共基础{};C类{};使用T1=BaseWrapper<Derived,Base>;使用T2=BaseWrapper<C,Base>;//在这里失败,但自定义消息会很好}

解决方案

[EWG] P1267R0:自定义约束诊断

<块引用>

不过,我想知道是否可以在那里发布自定义信息消息.

目前没有这样的原生特性作为概念的一部分,但有一篇 WG21/SD-1 论文专门讨论了这个主题:

<块引用>

设计

自定义诊断标准中已有先例:

[[已弃用(原因")]]静态断言(条件,原因)

我们建议添加一个新的属性,类似于 [[deprecated("reason")]] ,用于自定义约束诊断消息.让我们称之为新的attribute[[reason_not_used(reason")]] 现在:

template 需要 Correct_Regex_Syntax[[reason_not_used(无效的正则表达式语法")]]布尔匹配(string_view sv);

当这个属性被放置在一个函数上时,诊断消息将在以下情况下使用:

  • 由于任何原因(扣除/替换失败,需要子句约束失败、没有合适的转换等).
  • 函数调用没有找到匹配的重载,因此导致编译失败.

如今,当函数调用未能找到匹配项时,C++ 编译器通常会打印出所有考虑的候选者的列表.我们设想这个新属性可以添加到现有的诊断中,就像 static_assert 的诊断消息一样.

[...]

未来方向

该属性也可能用于类和别名为约束提供自定义诊断消息的模板失败和选择专业时(在类的情况下模板):

template 需要 FloatingPoint<T>||积分 T[[reason_not_used(元素类型必须是数字")]]结构矩阵{};矩阵<字符串>一种;#:#: 错误: 模板约束失败矩阵<字符串> a;^#:#: 注意: 不满足约束: 元素类型必须是数字#:#: 注: 在 ...

这个属性也可以附加到概念定义,并使用每当检查该概念的约束失败时.

它的听众是进化工作组 (EWG),据@DavisHerring(C++ 委员会成员)说,虽然没有对外发布,但被拒绝了:

<块引用>

@DavisHerring:

[...] 该论文在 2018 年被考虑并被拒绝"——也就是说,需要再次考虑新信息(例如现在是 2021 年,但实际上概念错误消息仍然很糟糕").

>

最近,论文的公开状态非常简短;对于像这样的旧论文,不幸的是参考文献是内部的.

然而,最有可能是受到 StackOverflow 问答的启发,这个话题在 r/cpp 上复活了,作为线程概念的自定义诊断",讨论了一种替代的、更简单的概念自定义诊断方法[强调我的]

<块引用>

概念的自定义诊断"

我想为概念提出"以下简单属性:

template [[requirement_failed(原因")]]概念 MyConcept =/*一些表达式*/;模板概念 MyConcept2 = 要求(T t){/*一些表达*/;} [[requirement_failed(原因")]];

目的应该很明显:原因";作为编译器发布请注意,当不满足要求时.

注意事项:

P1267R0,但我认为它只是没有以足够简单的方式放置或呈现它.在任何需要"的定义上允许该属性可能会结果一团糟.

在概念定义上允许它只会保持干净.它避免重复使用相同功能的各种功能概念.它避免过度使用该功能,因为不应该有过多的概念.

在我看来,作为界面一部分的概念应该提供诊断"消息作为最佳做法.

我认为我没有勇气、洞察力或时间将其变成正式提案,即使这是一件非常简单的事情.所以我认为,我只想在这里提一下.也很难想象有什么一些概念委员会尚未考虑类似的问题.

无论如何,我想引起一些注意.

作者明确提到他/她不希望就该主题发表正式论文.如果例如这个 SO Q&A 的 OP 认为这是一个重要的特征,一种方法是选择这个主题并将其(重新)形式化为一篇论文.

Concepts are great at pinpointing an error to the line of code where "a constraint was not satisfied".

I'm wondering, however, if it is possible to issue a custom informational message there. The upside of static_assert was exactly that possibility. Use case: Any library that wants to help the user in figuring out why a certain expression was not satisfying the constraints.

Here is a simple example, just to have some code. You might argue that any half-decent 'user' must be able to figure out the compiler's note "because 'is_base_of<Base, C>' evaluated to false", but more custom information could not hurt. There will be more complicated concepts for sure.


template<typename B, typename D> 
concept is_base_of = std::is_base_of_v<B, D>;

template <typename T, is_base_of<T> BaseType>
struct BaseWrapper { };  

int main() 
{
    class Base {};
    class Derived : public Base {};
    class C {};

    using T1 = BaseWrapper<Derived,Base>;
    using T2 = BaseWrapper<C,Base>;         // fails right here, but a custom message would be nice
}

解决方案

[EWG] P1267R0: Custom Constraint Diagnostics

I'm wondering, however, if it is possible to issue a custom informational message there.

There is currently no such native feature as part of Concepts, but there was a WG21/SD-1 paper that covered specifically this topic:

Design

There is already precedent in the standard for custom diagnostics:

[[deprecated("reason")]]

static_assert(cond, reason)

We propose adding a new attribute, similar to ​[[deprecated("reason")]]​, for custom constraint diagnostic messages. Let’s call this new attribute[[reason_not_used("reason")]]​ for now:

template​ <fixed_string Pattern>  
  requires Correct_Regex_Syntax<Pattern>  
  [[reason_not_used("invalid regex syntax")]]
bool​ match(string_view sv);

When this attribute is placed on a function, the diagnostic message would be used when:

  • The function was considered and rejected as a candidate for a function call, for any reason (deduction/substitution failure, requires clause constraint failure, no suitable conversion, etc).
  • The function call found no matching overload and thus lead to a compilation failure.

Today, when a function call fails to find a match, C++ compilers typically print out a list of all the candidates considered. We envision this new attribute as being additive to existing diagnostics, in the same way that static_assert​’s diagnostic message is.

[...]

Future Directions

This attribute could also potentially be used on class and alias templates to provide custom diagnostic messages for constraint failures and when selecting a specialization (in the case of class templates):

template​ <​typename​ T>  
  requires FloatingPoint<T> || Integral<T>  
  [[reason_not_used("the element type must be numeric")]]
struct​ matrix {};

matrix<string> a;

#:#:​error: ​template constraint failure 
matrix<string​>​ a;​
             ^
#:#:​note: ​constraints not satisfied: ​the element type must be numeric
#:#:​note: ​within ...

This attribute could also be attached to concept definitions, and used whenever checking that concept’s constraints fails.

Its audience was the Evolution Working Group (EWG), and according to @DavisHerring (C++ committee member), albeit not published externally, it was rejected:

@DavisHerring:

[...] that paper was considered in 2018 and "rejected"—that is, new information (like "It’s 2021 and in practice concept error messages are still bad") would be needed to consider it again.

Recently, papers have been given very brief public statuses; for older papers like this one, the references are unfortunately internal.

However, most likely inspired by this StackOverflow Q&A, the topic has resuscitated on r/cpp, as the thread Custom 'diagnostics' for concepts, which discusses an alternative, simpler approach to custom diagnostics for concepts [emphasis mine]

Custom 'diagnostics' for concepts

I'd like to 'propose' the following simple attribute for concepts:

template <typename T> [[requirement_failed("reason")]]
concept MyConcept = /*some expression*/;

template<typename T>
concept MyConcept2 = requires(T t) {    
    /*some expression*/;
} [[requirement_failed("reason")]];

The purpose should be quite obvious: "reason" is issued as a compiler note, when the requirements are not met.

Notes:

There is P1267R0, but I think it's just not put or presented it in a simple enough way. Allowing the attribute on any definition that 'requires' will likely result in a mess.

Allowing it on concept definitions only will keep things clean. It avoids duplication for various functions making use of the same concept. It avoids over-use of the feature, as there should not be an excessive amount of concepts.

In my view, concepts that are part of an interface should offer 'diagnostic' messages as a best practice.

I don't think I have the guts, insight or time to make this into an official proposal, even if it is a very simple thing. So I thought, I'd just mention it here. It's also hard to imagine that something similar has not been considered yet, by some concepts committee.

Anyway, I wanted to draw some attention to it.

The author explicitly mentions he/she would not like to go forward with a formal paper on the topic. If e.g. the OP of this SO Q&A sees this as an important feature, one approach would be to pick up and (re-)formalize this topic into a paper.

这篇关于如何通过自定义错误消息使概念失败 (C++20)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆