问题描述
我偶然发现了这一点:
#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;
};
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>
不完整的情况下尝试T
,而在{ {1}}完善了,那些应该给出不同的答案,您正在自找麻烦。
T
在您检查时还不完整,因此自然没有名称为Foo
的成员。这真的可能行不通。
因为这阻止了将概念与一些众所周知的模式(例如CRTP)一起使用。
以这种方式一起使用 ,是的。就像使用CRTP一样,您也无法直接访问传递到基类的template参数之外的任何内容,因此必须始终小心地推迟该类型的任何实例化,直到完成为止。
这最终是相同的原因:
a
不起作用。