Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用C++;强制类实现一组方法的20个概念 我想知道C++中是否有一种方法(特别是C++ 20)来为类/结构编写一些接口。_C++_Class_Templates_C++20_C++ Concepts - Fatal编程技术网

使用C++;强制类实现一组方法的20个概念 我想知道C++中是否有一种方法(特别是C++ 20)来为类/结构编写一些接口。

使用C++;强制类实现一组方法的20个概念 我想知道C++中是否有一种方法(特别是C++ 20)来为类/结构编写一些接口。,c++,class,templates,c++20,c++-concepts,C++,Class,Templates,C++20,C++ Concepts,例如,Java接口中有一个完全“抽象类”,用于将相关方法与空体分组: 界面动物 { 公共无效动物声(); 公开无效运行(); } C++中,可以使用纯虚方法声明来实现相同的行为。 类动物 { 公众: 虚拟void animalSound()=0; 虚空运行()=0; }; 但是使用虚拟方法会有运行时开销,我对继承不感兴趣。 因此,这种运行时成本应该是不必要的。我只想对我的“动物”类/结构进行编译时检查 有了C++20的概念,我确信构建一个构造是可以实现的 可以应用于类以保证提供了一组特定的

例如,Java接口中有一个完全“抽象类”,用于将相关方法与空体分组:

界面动物 { 公共无效动物声(); 公开无效运行(); }

C++中,可以使用纯虚方法声明来实现相同的行为。

类动物
{
公众:
虚拟void animalSound()=0;
虚空运行()=0;
};
但是使用虚拟方法会有运行时开销,我对继承不感兴趣。 因此,这种运行时成本应该是不必要的。我只想对我的“动物”类/结构进行编译时检查

有了C++20的概念,我确信构建一个构造是可以实现的 可以应用于类以保证提供了一组特定的方法

我想做的事情看起来有点像这样

template<typename Animal_> concept Animal =
requires()
{
  (Animal_{}); // default constructable

  (Animal_{}.animalSound());
  (Animal_{}.run());
};

其中,
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_); }
};
//给定以下代码
模板概念向量=
需要()
{
(Vector_{});//默认可构造
(Vector_{}.X())->Float;
(Vector_{}.Y())->Float;
};
[[nodiscard]]constexpr auto Pow2(const auto x)无例外
{
返回x*x;
}
[[nodiscard]]constexpr auto LengthPow2(Vector auto vec)无例外//使用Vector
{
返回Pow2(向量X())+Pow2(向量Y());
}
//现在我想实现一个向量
//我需要编译时检查,确保没有遗漏任何属性
结构向量mpl1
{
//编辑:正如@QuentinUK提到的,静态断言应该在公共范围内
//“如果在类的私有部分中
//可以通过私人会员,这不是您想要的。”
公众:
//编辑:正如@DavisHerring提到的,这是一条路要走
静态(向量);
公众:
constexpr VectorImpl1()noexcept=default;
constexpr VectorImpl1(float x,float y)noexcept:x_ux,y_ux(y){
私人:
浮点数x{};
浮动y{};
公众:
[[nodiscard]]constexpr float X()const noexcept
{返回x;}
[[nodiscard]]constexpr float Y()const noexcept
{返回y;}
};
结构向量mpl2
{
公众:
静态(向量);
公众:
constexpr VectorImpl2()noexcept=default;
constexpr VectorImpl2(float-rad,float-length)无例外:rad(rad),length(length){
私人:
浮动半径{};
浮动长度{};
公众:
[[nodiscard]]constexpr float X()const noexcept
{返回CalcX(rad,length);}
[[nodiscard]]constexpr float Y()const noexcept
{return CalcY(rad,length);}
};

可以,问题是为什么要这样做。 如果您的类型没有执行预期的操作,您将得到一个编译错误,对吗

如果出于某种原因希望在同一标头中获得编译错误,可以执行以下操作:

template <typename ...>
using void_t = void;    // available since c++17 in std

template <typename T>
using cow_test = void_t<
    decltype(std::declval<T>().moo(0)),
    decltype(std::declval<T>().chew(0))
>;

class cow {
  public:
    void moo(int);
    void chew(int);
};

using test_cow = cow_test<cow>;

class cat {
  public:
    void meaw(int);
    void chew(int);
};

using test_cat = cow_test<cat>;

不过,我怀疑您想要的是根据这些信息采取行动:基本上-如果我的类可以
moo()
-moo,否则
meaw


这是可以实现的,在概念出现之前,通过使用
检测习惯用法,我建议看一下:或者读一下这不是CRTP的目的吗?“所以这个运行时成本应该是不必要的。我只想对我的“动物”类/结构进行编译时检查。”我不理解这里的用例。你会使用某种多态性吗?也就是说,您是否要将该类型传递给不知道确切类型的对象?如果没有,那么就没有什么真正需要验证的了。如果是这样,那么您应该考虑一些接口,这些接口将接收并使用实现所述接口的对象。仅验证声明是否与概念匹配是没有意义的。返回类型测试
std::is_matching_concept
拼写为
C
,不过您必须将
静态断言
放在类后。静态断言可以在类内。(但是如果在类的私有部分,概念可以传递给私有成员,这不是您想要的。)
template <typename ...>
using void_t = void;    // available since c++17 in std

template <typename T>
using cow_test = void_t<
    decltype(std::declval<T>().moo(0)),
    decltype(std::declval<T>().chew(0))
>;

class cow {
  public:
    void moo(int);
    void chew(int);
};

using test_cow = cow_test<cow>;

class cat {
  public:
    void meaw(int);
    void chew(int);
};

using test_cat = cow_test<cat>;
r #1) C++
x86-64 gcc 10.1
Compiler options...
1
<Compilation failed>
x86-64 gcc 10.1 - 364ms
#1 with x86-64 gcc 10.1
<source>: In substitution of 'template<class T> using cow_test = void_t<decltype (declval<T>().moo(0)), decltype (declval<T>().chew(0))> [with T = cat]':

<source>:26:30:   required from here

<source>:8:33: error: 'class cat' has no member named 'moo'

    8 |      decltype(std::declval<T>().moo(0)),

      |               ~~~~~~~~~~~~~~~~~~^~~