细化概念时,在标准中始终如一地完成的方式是完全写出要细化的概念。例如,在[concepts.integral]中,SignedIntegral
像这样精简Integral
:
template<class T>
concept Integral = is_integral_v<T>;
template<class T>
concept SignedIntegral = Integral<T> && is_signed_v<T>;
为什么不能将精致的概念写成:
template<Integral T>
concept SignedIntegral2 = is_signed_v<T>;
SignedIntegral2
似乎具有与SignedIntegral
相同的含义,但它甚至没有在clang上编译。有这个原因吗?
答案 0 :(得分:18)
由于[temp.concept]/4,SignedIntegral2
的声明格式错误:
一个概念不应有关联的约束。
理解这一点的原因很重要。概念基本上是谓词。他们的工作是接受一系列参数(最常见的是一系列类型),并说出该概念是否得到满足。但是请考虑这两种不同的实现将给出什么答案:
SignedIntegral<int32_t>
是true
SignedIntegral<uint32_t>
是false
SignedIntegral<string>
是false
但是:
SignedIntegral2<int32_t>
是true
SignedIntegral2<uint32_t>
是false
SignedIntegral2<string>
是...未定义概念的全部要点是约束。 SignedIntegral2
中建议的替代性简洁声明将约束类型参数T
为Integral
。由于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>; }
重要的是概念必须始终是整体功能,这就是为什么不允许关联约束的原因。
请注意,出于概念满足的目的,可以肯定地将“未定义的”视为false
作为扩展,但这会给使用规则带来更多的麻烦,并且实现的复杂性肯定是不平凡的。将来某些标准可能会允许它们。我的水晶球目前在商店里,所以我不能肯定地说。