C++ 否定与德摩根';s定律不属于C++;20约束偏序

C++ 否定与德摩根';s定律不属于C++;20约束偏序,c++,language-lawyer,c++20,c++-concepts,demorgans-law,C++,Language Lawyer,C++20,C++ Concepts,Demorgans Law,规则指的是和或,但不指不: 这些规则基于和的定义: 否定(即!E1)是专门不处理的 因此,以下代码正确使用了偏序: void foo(auto i) requires std::integral<decltype(i)> { std::cout << "integral 1" << std::endl; } void foo(auto i) requires std::integral<decltype(i)> && tr

规则指的是和或,但不指不:

这些规则基于和的定义:

否定(即!E1)是专门不处理的

因此,以下代码正确使用了偏序:

void foo(auto i) requires std::integral<decltype(i)> {
    std::cout << "integral 1" << std::endl;
}

void foo(auto i) requires std::integral<decltype(i)> && true {
    std::cout << "integral 2" << std::endl;
}

int main() {
    foo(0); // integral 2
}
void foo(自动i)需要std::integral{
标准::cout
是否做出了不将否定作为约束规范化的一部分来处理的决定,以简化编译器供应商的实现

是的。这概括为在编译器中需要SAT解算器

增加了一个例子来说明这一点,尽管它没有提供决策的理由:

模板概念sad=false;
模板int f1(T)需要(!sad);
模板int f1(T)需要(!sad)&&true;
int i1=f1(42);//不明确的、sad原子约束表达式([temp.constr.atomic])
//不是由同一表达式构成的
模板概念不_sad=!sad;
模板int f2(T)要求不使用sad;
模板int f2(T)不需要_sad&&true;
int i2=f2(42);//好的,sad原子约束表达式都来自not u­sad
模板int f3(T)需要(!sad);
int i3=f3(42);//错误:由于替换失败,未满足相关约束
模板概念sad\u嵌套类型=sad;
模板int f4(T)需要(!sad_嵌套_类型);
int i4=f4(42);//好,sad嵌套类型中包含替换失败

特别要注意的是,
f3
f4
之间的区别。
是否需要!sad
意味着没有
sad
嵌套类型,或者存在一个不是
sad
的嵌套类型?它实际上意味着后者,而
f4
上的约束意味着前者。

这很快!尝试查找这方面的历史记录或我讨论过的主题:例如,但找不到此主题的参考文献。如果您有,将不胜感激。谢谢。@AmirKirsh没有这样的历史记录-此示例是作为响应而添加的。Core通常不添加语言功能的基本原理,因此没有包含这是一个很好的参考!值得在答案中添加链接。工作文件有时会详细说明建议背后的基本原理,因此它可能确实出现在某个地方。或者不出现。
13.5.3 Constraint normalization [temp.constr.normal]
1 The normal form of an expression E is a constraint that is defined
  as follows:
(1.1) The normal form of an expression ( E ) is the normal form of E.
(1.2) The normal form of an expression E1 || E2 is the disjunction
      of the normal forms of E1 and E2.
(1.3) The normal form of an expression E1 && E2 is the conjunction
      of the normal forms of E1 and E2.
void foo(auto i) requires std::integral<decltype(i)> {
    std::cout << "integral 1" << std::endl;
}

void foo(auto i) requires std::integral<decltype(i)> && true {
    std::cout << "integral 2" << std::endl;
}

int main() {
    foo(0); // integral 2
}
template<typename T>
concept not_integral = !std::integral<T>;

template<typename T>
concept not_not_integral = !not_integral<T>;

void foo(auto i) requires not_not_integral<decltype(i)> {
    std::cout << "integral 1" << std::endl;
}

void foo(auto i) requires std::integral<decltype(i)> && true {
    std::cout << "integral 2" << std::endl;
}

int main() {
    foo(0);
}
template<class P>
concept has_field_moo_but_not_foo
     = has_field_moo<P> && !has_field_foo<P>;
template<class P>
concept has_field_moo_but_not_foo
     = !(has_field_foo<P> || !has_field_moo<P>);
template <class T> concept sad = false;

template <class T> int f1(T) requires (!sad<T>);
template <class T> int f1(T) requires (!sad<T>) && true;
int i1 = f1(42);        // ambiguous, !sad<T> atomic constraint expressions ([temp.constr.atomic])
                        // are not formed from the same expression

template <class T> concept not_sad = !sad<T>;
template <class T> int f2(T) requires not_sad<T>;
template <class T> int f2(T) requires not_sad<T> && true;
int i2 = f2(42);        // OK, !sad<T> atomic constraint expressions both come from not_­sad

template <class T> int f3(T) requires (!sad<typename T::type>);
int i3 = f3(42);        // error: associated constraints not satisfied due to substitution failure

template <class T> concept sad_nested_type = sad<typename T::type>;
template <class T> int f4(T) requires (!sad_nested_type<T>);
int i4 = f4(42);        // OK, substitution failure contained within sad_­nested_­type