【发布时间】:2020-09-03 15:30:37
【问题描述】:
我想知道 C++(尤其是 C++20)中是否有办法为类/结构编写某种接口。
例如在 Java 中接口是一个完全“抽象类”,用于将相关方法与空主体进行分组:
interface Animal
{
public void animalSound();
public void run();
}
在 C++ 中,您可以使用纯虚方法声明来实现相同的行为。
class Animal
{
public:
virtual void animalSound() = 0;
virtual void run() = 0;
};
但是使用虚拟方法会产生运行时成本,而且我对继承不感兴趣。 所以这个运行时成本应该是不必要的。我只想对我的“动物”类/结构进行编译时检查。
借助 C++20 的概念,我确信构建一个构造是可以实现的 您可以应用到一个类以保证提供了一组特定的方法。
我试图做的看起来有点像这样。
template<typename Animal_> concept Animal =
requires()
{
(Animal_{}); // default constructable
(Animal_{}.animalSound());
(Animal_{}.run());
};
但我不确定这是不是很 C++。
(顺便问一下,有没有办法要求方法的返回类型是特定类型?)
我不确定如何将它附加到类/结构。
我的第一个想法是在类/结构中使用static_assert:
class Cow
{
private: // compile time type checking
static_assert(std::is_matching_concept<Animal, Cow>);
public:
void animalSound() const noexcept {}
void run() const noexcept {}
};
std::is_matching_concept 是我找不到的约束的占位符。
我正在寻找最佳实践反馈和建议来解决我的问题。
编辑 - 添加用例
// given the following code
template<typename Vector_, typename Float_=float> concept Vector =
requires()
{
(Vector_{}); // default constructable
(Vector_{}.X())->Float_;
(Vector_{}.Y())->Float_;
};
[[nodiscard]] constexpr auto Pow2(const auto x) noexcept
{
return x * x;
}
[[nodiscard]] constexpr auto LengthPow2(Vector auto vec) noexcept // the use of Vector
{
return Pow2(vec.X()) + Pow2(vec.Y());
}
// Now I want to implement a Vector
// and I want compile time checking, that I have no missed any properties
struct VectorImpl1
{
// EDITED: as @QuentinUK mentioned the static_assert should be in a public scope
// "If in the private part of a class the concepts
// can pass for private members which isn't what you'd want."
public:
// EDITED: as @DavisHerring mentioned this is the way to go
static_assert(Vector<VectorImpl1>);
public:
constexpr VectorImpl1() noexcept = default;
constexpr VectorImpl1(float x, float y) noexcept : x_(x), y_(y) {}
private:
float x_{};
float y_{};
public:
[[nodiscard]] constexpr float X() const noexcept
{ return x_; }
[[nodiscard]] constexpr float Y() const noexcept
{ return y_; }
};
struct VectorImpl2
{
public:
static_assert(Vector<VectorImpl2>);
public:
constexpr VectorImpl2() noexcept = default;
constexpr VectorImpl2(float rad, float length) noexcept : rad_(rad), length_(length) {}
private:
float rad_{};
float length_{};
public:
[[nodiscard]] constexpr float X() const noexcept
{ return CalcX(rad_, length_); }
[[nodiscard]] constexpr float Y() const noexcept
{ return CalcY(rad_, length_); }
};
【问题讨论】:
-
这不就是 CRTP 的用途吗?
-
"所以这个运行时成本应该是不必要的。我只想对我的“动物”类/结构进行编译时检查。“我不明白你的用例在这里.你会使用某种多态性吗?也就是说,您是否要将该类型传递给不知道确切它是什么类型的东西?如果不是,那么就没有什么可以验证的了。如果是这样,那么你应该有一些接口可以接收和使用实现所述接口的对象。仅验证声明与概念匹配是没有意义的。
-
std::is_matching_concept<C,T>拼写为C<T>,尽管您必须将static_assert放在类之后。 -
static_assert 可以在类中。 (但如果在类的私有部分,概念可以传递给私有成员,这不是您想要的。)
标签: c++ class templates c++20 c++-concepts