为什么概念细化不能使用简洁的语法

Bar*_*rry 15 c++ c++-concepts c++20

在完善概念时,在标准中始终如一地完成的方式是完全写出正在改进的概念.例如,在[concepts.integral]中,SignedIntegral精炼Integral如下:

template<class T>
  concept Integral = is_integral_v<T>;
template<class T>
  concept SignedIntegral = Integral<T> && is_signed_v<T>;
Run Code Online (Sandbox Code Playgroud)

为什么不能将精致的概念写成:

template<Integral T>
  concept SignedIntegral2 = is_signed_v<T>;
Run Code Online (Sandbox Code Playgroud)

SignedIntegral2似乎具有相同的明显含义SignedIntegral,但它甚至没有在clang上编译.是否有一个原因?

Bar*_*rry 19

SignedIntegral2由于[temp.concept]/4,声明格式不正确:

概念不应具有相关约束.

了解其原因非常重要.概念基本上是谓词.他们的工作是采取一系列论点(最常见的是一系列类型)并说出这个概念是否满足.但请考虑这两种不同实现的答案:

  • SignedIntegral<int32_t>true
  • SignedIntegral<uint32_t>false
  • SignedIntegral<string>false

但:

  • SignedIntegral2<int32_t>true
  • SignedIntegral2<uint32_t>false
  • SignedIntegral2<string> 是...未定义

概念的全部意义在于约束.所提出的替代方案,简洁的声明中SignedIntegral2 约束的类型参数TIntegral.既然string不满足Integral,我们甚至不能问这是否是一个问题SignedIntegral2.

换句话说,SignedIntegral是一个总函数但是SignedIntegral2只是在Integral类型上定义的部分函数.如果我们将两者都写成实际的函数,这可能会更清楚:

template <typename T>
constexpr bool SignedIntegral() { return Integral<T> && is_signed_v<T>; }

template <Integral T>
constexpr bool SignedIntegral2() { return is_signed_v<T>; }
Run Code Online (Sandbox Code Playgroud)

重要的是概念总是总函数,这就是不允许相关约束的原因.


请注意,作为false概念满足的目的,它肯定可以作为处理"未定义"的扩展,但这会给包含规则增加额外的皱纹,这肯定是非平凡的实现复杂性.一些未来的标准肯定可能允许它们.我的水晶球目前在商店,所以我不能肯定地说.

  • @HolyBlackCat:是的,但是`SignedIntegral2 <string>`是未定义的,因为对于具有非整数类型的`SignedIntegral2`没有有效的实例化.这就是模板约束失败时的含义.现在,如果有一个单独的"SignedIntegral2"定义不受约束,那么可以实例化.从技术上讲,它不会"未定义"; 它会是不合理的 (2认同)
  • 这实际上是两个不同的问题."为什么我们不能有约束的概念"和"为什么我们不能将概念的约束定义为代表连词". (2认同)