【发布时间】:2021-04-07 10:09:00
【问题描述】:
我正在尝试通过 CRTP 和 requires 子句来实现一种静态多态性。
我想要实现的是在引用 CRTP 基类的函数中调用可能被覆盖的函数。
我通过以下方法使其与 GCC 10 和 11 一起工作:
#include <iostream>
template<typename T>
class Base
{
public:
void f() const requires T::IsOverridden
{ static_cast<T const *>(this)->f(); }
void f() const
{ std::cout << "Fallback f()" << std::endl; }
};
class A : public Base<A>
{
public:
static constexpr bool IsOverridden = true;
public:
void f() const
{ std::cout << "Overridden f()" << std::endl; }
};
class B : public Base<B> {};
template<typename T>
void f(Base<T> const &x)
{ x.f(); }
int main()
{
A const a;
B const b;
f(a);
f(b);
return 0;
}
但是,Clang 11 不喜欢这段代码:
test.cpp:7:30: error: no member named 'IsOverridden' in 'A'
void f() const requires T::IsOverridden
~~~^
test.cpp:14:18: note: in instantiation of template class 'Base<A>' requested here
class A : public Base<A>
^
test.cpp:7:30: error: no member named 'IsOverridden' in 'B'
void f() const requires T::IsOverridden
~~~^
test.cpp:24:18: note: in instantiation of template class 'Base<B>' requested here
class B : public Base<B> {};
^
哪个编译器是正确的?
注意:我使用布尔成员来表示覆盖,因为我希望它与嵌套在模板类中的类一起使用,这是我在这种情况下想出的唯一方法。
【问题讨论】:
-
CRTP 的问题是
Derived是Base<Derived>定义中的不完整类型(通常是完整的inside 成员定义)。 Clang 似乎是对的。 -
作为替代方案,您可以使用
if constexprDemo。 -
@Jarod42 谢谢。 Clang 接受的另一种解决方法:wandbox.org/permlink/Ki8pshYJpmVYzSQx。当类被实例化时,Clang 是否正确地实例化带有尾随 requires 子句的函数?我也测试过MSVC,同意G++。
-
它不实例化函数,但类可以检查签名和模板函数是否存在非依赖(关于函数模板参数,因为模板类参数现在已修复)的东西。
-
@Jarod42 Clang 错误。请参阅 Richard Smith 的评论:bugs.llvm.org/show_bug.cgi?id=44833#c4。 (感谢 PilarLatiesa 指出这一点)。
标签: c++ c++20 c++-concepts