当我的基类没有实现成员函数时,我想触发
static_assert
。
#include<type_traits>
template<typename T>
struct AlwaysFalse : public std::false_type {};
struct B
{
template<typename S>
void foo(){}
};
template <typename T,typename S>
struct A:T
{
auto foo(){
if constexpr (requires{T::template foo<S>();})
return 1;
else
static_assert(AlwaysFalse<A>::value,
"foo is not implemented.");
}
};
int main()
{
A<B,double> a;
a.foo();
}
这可以在 gcc 12.2 中编译,但无法使用 clang 16 和 clang trunk 进行编译。 如果成员函数
foo
不是模板,clang 也会编译它。
这里哪个编译器是正确的?我想是GCC,因为基类成员函数在那里并且它不应该读取
AlwaysFalse
。 我的代码是否符合 C++ 标准?
我还有一个解决方法,通过在需要表达式中创建一个对象
if constexpr (requires(T t){t. template foo<S>();})
这两个编译器都会再次编译。
GodBolt 模板版本:https://godbolt.org/z/oTWPhWE99
GodBolt 非模板版本:https://godbolt.org/z/7b5xcvYYv
GodBolt 解决方法:https://godbolt.org/z/6Taj7c515
首先,正确的大写是“Godbolt”。该网站以其创建者 Matt Godbolt 的名字命名。
我们可以通过将代码简化为:
来验证实现分歧确实与编译器认为应该实例化
if constexpr
的子语句无关。
struct B
{
template<typename S>
void foo(){}
};
template <typename T,typename S>
struct A : T
{
auto foo(){
static_assert(requires{T::template foo<S>();});
}
};
int main()
{
A<B,double> a;
a.foo();
}
在这里我们再次看到只有 Clang 有问题。但是,如果您在
T::template foo<S>();
的主体中确实有语句 A::foo
,那么 Clang 就没有问题,所以显然 Clang 并不认为它实际上是格式错误的。这意味着 requires
表达式应该为 true。结论:Clang bug。