C++20 概念是否取代其他形式的约束?

Mar*_*per 6 c++ enable-if c++-concepts c++20 void-t

C++20 已经登陆,带来了概念。如果一个项目现在开始并且仅针对 C++20 和更高版本的标准,那么说以前的约束形式现在被概念和子句取代是否合适requires

是否存在某些情况下enable_ifvoid_t仍然需要,而概念无法替代它们?

例如,std::bit_cast被限制为要求ToFrom类型具有相同的大小,并且两种类型都可以轻松复制。

来自 cppreference:

仅当 sizeof(To) == sizeof(From) 并且 To 和 From 都是 TriviallyCopyable 类型时,此重载才参与重载决策。

MSVC 标准库通过enable_if_t表达式来限制这一点,而 libcxx 选择子句requires

微软VC:

enable_if_t<conjunction_v<bool_constant<sizeof(_To) == sizeof(_From)>, is_trivially_copyable<_To>, is_trivially_copyable<_From>>, int> = 0
Run Code Online (Sandbox Code Playgroud)

libcxx:

requires(sizeof(_ToType) == sizeof(_FromType) &&
         is_trivially_copyable_v<_ToType> &&
         is_trivially_copyable_v<_FromType>)
Run Code Online (Sandbox Code Playgroud)

它们通过不同的语言特征执行相同的逻辑运算。

重申我的问题,是否存在无法从一种约束方法转换为另一种约束方法的情况?我知道有很多东西概念requires可以做到enable_if和/或void_t不能做到,但是从另一个方向看也可以这么说吗?针对 C++20 及更高版本的全新代码库是否需要依赖这些旧的语言结构?

sig*_*gma 0

我不知道这种情况,实际上您可以直接将 MSVC 示例中的连词复制到子句中requires,就像使用任何编译时布尔可测试表达式一样。尽管理想情况下,这些要求将在实际概念中得到体现:

template<typename FromType, typename ToType>
concept bit_castable_to = requires (...);
Run Code Online (Sandbox Code Playgroud)

它更容易重用,并允许您从更具表现力的语法中受益:

template<typename ToType, bit_castable_to<ToType> FromType>
// or
template<typename ToType>
ToType bit_cast(bit_castable_to<ToType> const auto& from);
Run Code Online (Sandbox Code Playgroud)

这也改进了错误输出的结构,现在直接提到您选择的类型未能满足该bit_castable_to概念,例如因为is_trivially_copyable您的类 Foo 的计算结果为 false。然而,一个实际问题是概念可以由任意深度的其他概念组成,因此失败的根源可能被埋在长消息流中。

除了这个更简单的示例之外,enable_if还可以用于根据编译时约束提供不同的实现,包括函数重载情况下的不同返回类型。if constexpr这也可以通过某种概念组合和auto返回类型推导(也可以受概念约束)以更易读的方式完成。

我知道的主要用途在这个问题void_t中进行了描述,但这也可以使用概念来更优雅地表达,例如

template<typename Type>
concept has_member =
    requires (Type t) { t.member; };
// or
    requires { typename Type::member; };
Run Code Online (Sandbox Code Playgroud)

您还可以使其更具体:

template<typename Type>
concept has_int_member = 
    requires (Type t) { 
        { t.member } -> std::same_as<int&>;
    };
// or
    std::same_as<int, typename Type::member>;
Run Code Online (Sandbox Code Playgroud)

我认为这种语法比混乱的语法更容易看懂decltype,而且std::declval有时这是一种必要的邪恶。

总而言之,我认为没有理由继续使用enable_ifvoid_t装置,除非需要支持较旧的编译器。我个人很高兴再也不会读或写一篇文章。概念更具表现力,而且由于通用 C++ 代码存在约束是很常见的,因此我认为拥有一种简单的方法来编写至少语法代码作为代码是一项巨大的财富。