如何避免这种讨厌的概念陷阱(取决于顺序)

How to avoid this nasty concept trap (depending on order)

下面的代码取决于定义的概念是before还是afterclass。目的是检查是否可以从 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。要获得预期的结果,必须在 class 之后定义概念。

我本以为上面的代码会出现以下两种情况之一:

  1. 一切正常
  2. 编译器给出警告或错误(提示我们的错误,如果是的话)请注意,当使用例如Quantity<T> 而不是概念中的 Quantity,发出编译器错误,因为 Quantity<T> 在这一点上没有意义。

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

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

There might be a "good reason" for this, "because compilers work a certain way", but I find this pretty flawed.

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

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

即使在ns之前定义了is_compatible也满足。

现在,如果您的概念与 ADL 无关,并且您的表达式确实是 function-styled 转换,那么只需限定类型(或模板名称)

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