概念是 SFINAE 的变体吗

jac*_*k X 3 c++ language-lawyer c++20

SFINAE 是一种允许在模板化函数的直接上下文中使用无效表达式和/或类型的技术,而似乎concept具有相同的效果,因为我们只允许在如果所有表达式和/或类型都有效,则概念定义和约束表达式为 true,否则为 false。在我看来,SFINAE 无法做任何超出 SFINAE 所能做的事情,反之亦然。concept

我的理解对吗?如果不是,什么情况下我们只能使用这个概念,或者使用SFINAE而使用其他方式会导致错误?如果不存在这样的场景,这个概念是否仅仅是使用 SFINAE 技术的优雅/现代方式(即它们本质上是等效的)?

更新:

IMO,唯一的区别是,我们想要检查的某些表达式和类型分散在 SFINAE 的声明中,相比之下,我们想要检查的某些表达式和类型被收集在 单个概念定义的约束表达式中,并使用声明中声明。它们的效果本质上依赖于无效的表达式和类型concept

Jef*_*ett 8

它们并不等同。概念可以出现在更多地方,并且通过包含进行部分排序。一些例子:

1. 概念包含可用于对重载进行排序。对于 SFINAE,这是一个错误

template <typename T>
auto overload(T) -> std::enable_if_t<std::is_copy_constructible_v<T>>;
template <typename T>
auto overload(T) -> std::enable_if_t<std::is_move_constructible_v<T>>;

void test() {
  overload(1); // error: ambiguous
}
Run Code Online (Sandbox Code Playgroud)

有了概念,这是有效的

void overload(std::copy_constructible auto);
void overload(std::move_constructible auto);

void test() {
  overload(1);
}
Run Code Online (Sandbox Code Playgroud)

2. 类似地,概念包含可用于对部分特化进行排序。

3. 非模板成员函数上允许使用概念,因此它们可以约束特殊的成员函数。

由于复制构造函数不是模板,因此 SFINAE 永远不会适用。当在概念之前需要条件行为时(例如,如果类模板的模板参数本身很简单,则需要简单的复制构造函数),则必须有条件地引入不同的基类。

4.概念可以限制演绎。

人们可以静态断言返回的类型满足您的要求,而无需断言精确类型。

std::integral auto i = 1;
Run Code Online (Sandbox Code Playgroud)

5. 概念可以用在缩写函数模板中。

void f(std::integral auto);
Run Code Online (Sandbox Code Playgroud)