首页 > 解决方案 > 如何避免这个讨厌的概念陷阱(取决于顺序)

问题描述

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

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. 编译器给出警告或错误(提示我们的错误,如果它是一个) 请注意,当使用 egQuantity<T>而不是Quantity在概念中时,会发出编译器错误,因为Quantity<T>此时没有意义。

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

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

标签: c++templatescompiler-warningsc++20c++-concepts

解决方案


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

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

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

并且即使is_compatible之前定义过也会满足ns

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

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

推荐阅读