请参考以下c++ 20代码:
template<bool op>
class Person
{
const bool own_pet;
public:
Person() : own_pet(op) {}
consteval bool OwnPet() const { return own_pet; }
consteval bool OwnPetC() const { return true; }
void PatPet() const {}
};
template<typename T>
concept MustOwnPet = requires(T obj) {
requires obj.OwnPet();
};
void pat(const MustOwnPet auto& p)
{
p.PatPet();
}
template<typename T>
concept MustOwnPetC = requires(T obj) {
requires obj.OwnPetC();
};
void pat_c(const MustOwnPetC auto& p)
{
p.PatPet();
}
int main()
{
// Error in gc 12.1 with -std=c++20:
// in 'constexpr' expansion of 'obj.Person<true>::OwnPet()'
// <source>:16:24: error: 'obj' is not a constant expression
// Also doesn't compile in clang 14.0.0 with -std=c++20
// pat(Person<true>());
// Error in clang 14.0.0 with -std=c++20
// Compiles fine in gcc 12.1 with -std=c++20
pat_c(Person<true>());
return 0;
}
我的理解是Person::OwnPet()
和Person::OwnPetC()
都是编译时函数,因为op
是main()
实例化的编译时函数。
为什么pat()
不能编译?请查看代码注释中的错误。
pat_c()
只在clang
中编译失败,在gcc
中编译正常。哪个编译器是正确的?
问题是那个叫obj
参数不是一个常数表达式。因此,它不能在需要常量表达式的求值上下文中使用。例如,我们不能使用obj
作为模板非类型形参(TNP),因为TNP必须是编译时常数,而obj
不是。
哪个编译器是正确的?
这似乎是在这里提交的gcc中的一个错误
以下代码适用于GCC 12.1
和-std=c++20
。我不熟悉你想要实现的,但我想这里的问题是成员变量,这是相同的所有模板实例,因此应该是一个static constexpr
。如果是这种情况,OwnPet()
可以在编译时求值。在另一种情况下,对于我们人类来说,它也可以在编译时计算,这是合乎逻辑的,但我想编译器不会(因为访问成员变量而不是const表达式)
template<bool op>
class Person
{
static constexpr bool own_pet = op;
public:
Person() {}
consteval bool OwnPet() const { return own_pet; }
consteval bool OwnPetC() const { return true; }
void PatPet() const {}
};
template<typename T>
concept MustOwnPet = requires(T obj) {
requires obj.OwnPet();
};
void pat(const MustOwnPet auto& p)
{
p.PatPet();
}
template<typename T>
concept MustOwnPetC = requires(T obj) {
requires obj.OwnPetC();
};
void pat_c(const MustOwnPetC auto& p)
{
p.PatPet();
}
int main()
{
pat(Person<true>());
pat_c(Person<true>());
return 0;
}