可以根据不完整的类型检查概念吗

use*_*329 2 c++ c++-concepts c++20

我偶然发现了这个:

#include <type_traits>
#include <concepts>

template<class T>
concept IsFoo = requires(T a)
{
    {a.a} -> std::same_as<int>;
};

#if 1
// Will not compile, because Foo currently has incomplete type
template<IsFoo AFoo>
struct AcceptsFoo
{};
#else
template<class AFoo>
struct AcceptsFoo
{};
#endif

struct Foo
{
    int a;
    int b;

    AcceptsFoo<Foo> obj;
};
Run Code Online (Sandbox Code Playgroud)

https://gcc.godbolt.org/z/j43s4z

其他变体 (crtp) https://gcc.godbolt.org/z/GoWfhq

Foo 是不完整的,因为它必须实例化AcceptsFoo,但要这样做,Foo必须是完整的,否则无法检查IsFoo。这是 GCC 中的错误,还是标准这么说?后者会令人难过,因为这会阻止将概念与一些众所周知的模式(例如 CRTP)一起使用。

我注意到 clang 确实给出了类似的错误:https : //gcc.godbolt.org/z/d5bEez

Bar*_*rry 6

您可以根据不完整的类型检查概念 - 但如果该概念检查实际上需要对需要它完成的类型进行任何操作,那么概念检查就会失败。

即使在那里,您也必须小心,因为允许(并将)缓存概念检查以更快地编译实现 - 因此,如果您尝试C<T>whileT不完整并在T完成时再次尝试,并且这些应该给出不同的答案,您会问为麻烦。

Foo在您检查它时还没有完成,所以自然它没有名为a. 这真的不可能奏效。

因为这会阻止概念与一些众所周知的模式(例如 CRTP)一起使用。

以这种方式一起使用,是的。与使用 CRTP 一样,您也无法直接访问传递给基类的模板参数的任何内容,您始终必须小心延迟该类型的任何实例化,直到它完成。

这最终是相同的原因:

template <typename Derived>
struct B { 
    typename Derived::type x;
};

struct D : B<D> {
    using type = int;
};
Run Code Online (Sandbox Code Playgroud)

不起作用。

  • @NoSenseEtAl这不是完整与不完整的问题——程序中的一个点之间的类型有很多事情可以改变。如果您有一个概念检查,例如...“foo(t)”,那么“HasFoo&lt;T&gt;”可能在某个时刻为“false”,然后添加一个重载,然后它变为“true”。完整/不完整只是其中一个示例,而且可能不是最常见的示例。 (3认同)