简体   繁体   English

自引用 c++20 概念

[英]Self referential c++20 concepts

What is the moral equivalent to the following invalid code?以下无效代码的道德等价物是什么?

// Suppose you want to check, as part of a concept,
// if some operation on a type results in a type that models such concept.
// you cannot constrain the resulting type with the same concept
// in the same way you can't have self referential types
// (that would result in recursive definitions)

template<class T>
concept Int = requires(const T& a, const T& b) {
  { a + b } -> Int; // compiler don't know what to do
};

Suppose you want to check, as part of a concept, if some operation on a type results in a type that models such concept.假设您要检查作为概念的一部分,对类型的某些操作是否会导致模型化此类概念的类型。

That's infinite recursion.那是无限递归。 Like any functional recursion, you have to have a terminal condition.像任何函数递归一样,您必须有一个终止条件。 The normal way to define a terminal condition for template arguments is via a specialization.为模板 arguments 定义终止条件的常规方法是通过特化。 But concept s explicitly cannot be specialized, so there can be no terminal condition.但是concept不能明确地特化,所以不能有终结条件。

It's also logically incoherent, since you're trying to write a definition by using the thing you're trying to define.它在逻辑上也是不连贯的,因为你试图通过使用你试图定义的东西来编写一个定义。 There is no "moral equivalent" to something that by definition doesn't make sense.没有“道德上的等价物”来定义根据定义没有意义的东西。

Your concept appears to be saying " T shall be a thing that I can add to another T and yield..." what?您的概念似乎是在说“ T应该是我可以添加到另一个T并产生的东西......”什么? Do you want it to be able to yield some unrelated type U which can be added to another U to yield... again, what?您是否希望它能够产生一些不相关的U类型,可以将其添加到另一个U以产生...再次,什么? Even ignoring that question, should U be able to be added to T ?即使忽略这个问题, U是否应该能够被添加到T And if so, what should that yield?如果是这样,那应该产生什么?

When writing a concept, start with the use case , start by deciding what operations you want to perform.编写概念时,从用例开始,先决定要执行的操作。

It is possible to do such recursive template check, but it makes code difficult to read.可以进行这种递归模板检查,但它使代码难以阅读。 The principle is to forward recursive template check to a function found by dependent name look up, whose constraints will only be verified if the type does not already belong to a list of already checked types... If the type belong to the list of already checked type, the function is disabled by SFINAE, and an other function that does not recursively refers to the concept is selected by overload resolution:原理是将递归模板检查转发到通过依赖名称查找找到的function,只有当类型不属于已检查类型列表时才会验证其约束...如果类型属于已检查类型列表检查类型,function 被 SFINAE 禁用,另一个不递归引用该概念的 function 由重载决议选择:

See it in action: compiler-explorer-link实际操作: compiler-explorer-link

#include <type_traits>

namespace trying{

    struct to_do{};

    template <class...Checked, class T>
    std::enable_if_t <(std::is_same_v <T,Checked> || ...), std::true_type> 
    too_complex(T &&, to_do);

    template <class...Checked, class T>
    std::false_type 
    too_complex(T &&,...);
}

template <class U, class T, class...Checked>
concept Integer_= requires(const T& a, const T& b, const U& to_be_readable)
   {
   requires decltype(too_complex <T, Checked...> (a + b, to_be_readable))::value ;
   };

template <class T, class...Checked>
concept Integer = Integer_ <trying::to_do, T, Checked...>;

namespace trying{
    template <class...Checked, class T>
    requires (Integer <T, Checked...>)
    std::enable_if_t <!(std::is_same_v <T,Checked> || ...), std::true_type> 
    too_complex(T &&, to_do);
}

struct x{
    auto
    operator + (x) const -> int;
};
struct y{
    auto
    operator + (y) const -> void*;
};

struct z2;
struct z1{
    auto
    operator + (z1) const -> z2;
};
struct z2{
    auto
    operator + (z2) const -> z1;
};

static_assert (Integer <int>);
static_assert (Integer <x>);
static_assert (!Integer <y>);
static_assert (Integer <z1>);
static_assert (Integer <z2>);

So yes it is possible... but I don't think it should be done.所以是的,这是可能的……但我认为不应该这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM