【问题标题】:How to avoid this nasty concept trap (depending on order)如何避免这个讨厌的概念陷阱(取决于顺序)
【发布时间】:2020-09-03 16:58:42
【问题描述】:

以下代码取决于该概念是定义在类之前还是之后。目的是检查是否可以从T 构造Quantity。我已经把它去掉了,只显示了复制构造的测试。

template <typename T>
concept is_compatible = requires( T & t ) { Quantity( t ); }; // note: not Quantity<T> !

template <typename T>
class Quantity
{};

class X{};        

int main() 
{

    std::cout << is_compatible<Quantity<X>>;
    std::cout << is_compatible<X>;
}

对于给定的代码,输出是 00,而不是预期的 10。要获得预期的结果,必须在类之后定义概念。

对于上面的代码,我会想到两件事之一:

  1. 它按预期工作
  2. 编译器给出警告或错误(提示我们的错误,如果是一个错误)请注意,当使用例如Quantity&lt;T&gt; 而不是概念中的Quantity,会发出编译器错误,因为此时Quantity&lt;T&gt; 没有意义。

我没想到第三个,沉默的选择!这可能有一个“很好的理由”,“因为编译器以某种方式工作”,但我发现这很有缺陷。

如果行为正确,编写此代码的更好方法是什么?

【问题讨论】:

标签: c++ templates compiler-warnings c++20 c++-concepts


【解决方案1】:

这可能有一个“很好的理由”,“因为编译器以某种方式工作”,但我发现这有很大的缺陷。

没有它,概念就不会那么有用。您将无法检查依赖于 ADL 的函数调用表达式是否有效。这对声明满足了你的概念

namespace ns {
    struct X {};
    void Quantity(X) {}
}

即使is_compatiblens之前定义也会满足。

现在,如果您的概念与 ADL 无关,并且您的表达式确实打算成为函数样式的强制转换,那么只需限定类型(或模板名称)

template <typename T>
concept is_compatible = requires( T & t ) { ::Quantity( t ); };
                                          // ^ -- in the absence of a preceding declaration, error here

【讨论】:

  • 是的,在写完问题后不久就认为Quantity 可以是任何函数。不过,我不明白为什么“ADL 阶段”找不到复制构造函数,如果它可以找到任何函数......叹息。
  • @non-user - ADL 只查找免费函数
  • 好的,回到学校facepalm::Quantity 的有趣之处在于:gcc(当然)如果它在类之前正确地发出错误。 MSVC(理解简单人的编译器)在这两种情况下都会编译并执行预期的操作。但是,智能感知仍然会在错误之前或之后显示错误。这是一个混乱的世界。 (是的,我知道概念还没有准备好)
  • 我一开始就讨厌这种“检查复制构造函数/转换”,我真正想做的只是检查T 是否已经是Quantity
  • @non-user - 默认情况下,MSVC 对模板的处理是非标准的。您必须明确关闭许可模式才能获得标准一致性的外观。至于检查 T 是否是 Quantity 特化,可以使用简单的类型特征(即使在 C++98 中)来完成。这个概念只需要包装它。
猜你喜欢
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 2019-07-14
  • 1970-01-01
  • 2015-04-08
  • 1970-01-01
相关资源
最近更新 更多