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
您可以根据不完整的类型检查概念 - 但如果该概念检查实际上需要对需要它完成的类型进行任何操作,那么概念检查就会失败。
即使在那里,您也必须小心,因为允许(并将)缓存概念检查以更快地编译实现 - 因此,如果您尝试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)
不起作用。