考虑以下课程:
struct C
{
/* Class contents, without any arithmetic operator... */
constexpr operator int() noexcept; // Implicit conversion to int
};
Run Code Online (Sandbox Code Playgroud)
我的问题是:
std::sort当前使用默认<运算符的标准算法?LessThanComparable概念吗?LessThanComparable.是概念定义的主体还是需要阻止未评估的上下文?例如.我可以std::declval安全使用吗?
template<typename T>
concept bool SomeConcept = requires(T a) {
{ a.someFunction(std::declval<int>()) } -> int;
};
Run Code Online (Sandbox Code Playgroud) 在完善概念时,在标准中始终如一地完成的方式是完全写出正在改进的概念.例如,在[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上编译.是否有一个原因?
我正在尝试 C++20 的概念,要么std::swappable_with是未定义的(Visual Studio,使用/std:c++latest),要么它的约束与下面的 MCVE 不匹配(g++10 使用-std=c++2a)——也就是说,int不能与int(!) . 有什么办法解决这个问题?如果int不能与 交换int,我看不到任何工作。
#include <concepts>
template <typename T, typename U>
requires std::swappable_with<T,U>
void mySwap(T& t, U& u)
{
T temp = t; t = u; u = temp;
}
int main()
{
int x, y;
mySwap(x, y);
return 0;
}
Run Code Online (Sandbox Code Playgroud) 请注意,在提出此问题后,缺陷报告更改了下面提到的行为。见问题末尾。
考虑以下:
// Variant 1
template<auto> struct require_constexpr;
template<typename R>
constexpr auto is_constexpr_size(R&& r) {
return requires { typename require_constexpr<std::ranges::size(std::forward<R>(r))>; };
}
static_assert(!is_constexpr_size(std::vector{1,2,3,4}));
static_assert(is_constexpr_size(std::array{1,2,3,4}));
Run Code Online (Sandbox Code Playgroud)
这里的目标不是is_constexpr_size函数本身,而是找到一个 ( requires) 表达式,确定范围类型的大小是编译时常量,以便可以在按顺序通过转发引用获取任何范围的函数中使用它if constexpr基于它进行切换。
不幸的是,这不起作用,因为r它是引用类型并且不能在常量表达式中使用,尽管std::array调用std::range::sizes永远不会访问引用的对象。
变体 2:在函数参数中替换为 会改变这一点R&&。R非引用类型变量的常量表达式要求较弱,MSVC 和 GCC 都接受经过此更改的代码,但 Clang 仍然不接受。我的理解是,目前有一项更改规则的提案,以便 with 的变体R&&也能按预期工作。
然而,在实现这一点之前,我正在寻找一种替代方案,不需要将参数限制为非引用类型。我也不想依赖于范围的类型,例如默认可构造的类型。因此我无法构造正确类型的临时对象。std::declval也无法使用,因为std::ranges::size需要评估。
我尝试了以下方法:
// Variant 3
return requires (std::remove_reference_t<R> s) { typename require_constexpr<std::ranges::size(std::forward<R>(s))>; };
Run Code Online (Sandbox Code Playgroud)
这被 MSVC 接受,但不被 …
以下代码在 static_assert 中失败:
#include <iostream>
#include <concepts>
#include <vector>
template <typename T>
concept container_type = requires(T& t) {
typename T::value_type;
typename T::reference;
typename T::iterator;
{ t.begin() } -> std::same_as<typename T::iterator>;
{ t.end() } -> std::same_as<typename T::iterator>;
};
// overload (0), fallback case
template <typename T>
constexpr int foo(const T& o) {
return 0;
}
// overload (1), using the concept
constexpr int foo(const container_type auto& o) {
return 1;
}
// overload (2), using template template parameter
template <typename T, …Run Code Online (Sandbox Code Playgroud) 在关于概念N3701的最新论文中,该sort算法有以下示例:
template<typename Cont>
requires Sortable<Cont>()
void sort(Cont& cont)
Run Code Online (Sandbox Code Playgroud)
其中Sortable概念被定义为
template<typename T>
concept bool Sortable()
{
return Permutable_container<T>() && Totally_ordered<Value_type<T>>();
}
Run Code Online (Sandbox Code Playgroud)
其中Totally_ordered,毫不奇怪,定义为
template<typename T>
constexpr bool Totally_ordered()
{
return Weakly_ordered<T>() && Equality_comparable<T>();
}
Run Code Online (Sandbox Code Playgroud)
反过来Equality_comparable被定义为
template<typename T>
constexpr bool Equality_comparable()
{
return requires(T a, T b) {
{a == b} -> bool;
{a != b} -> bool;
};
}
Run Code Online (Sandbox Code Playgroud)
我没有找到定义Weakly_ordered,但我相信它应该是这样的(我是对的吗?)
template<typename T>
constexpr bool Weakly_ordered()
{
return requires(T …Run Code Online (Sandbox Code Playgroud) C++ 20草案[concept.default.init] 没有精确定义default_initializable
template<class T>
concept default_initializable = constructible_from<T> &&
requires { T{}; } &&
is-default-initializable <T>; // exposition-only
Run Code Online (Sandbox Code Playgroud)
并用以下词语描述is-default-initializable应该做什么:
对于 type
T,is-default-initializable <T> 为真当且仅当变量定义
T t;对于某些发明的变量 t 是良构的;否则为假。访问检查就像在与 T 无关的上下文中执行。仅考虑变量初始化的直接上下文的有效性。
在cppreference 上,我们找到了以下可能实现的建议:
template<class T>
concept default_initializable = constructible_from<T> &&
requires { T{}; } &&
is-default-initializable <T>; // exposition-only
Run Code Online (Sandbox Code Playgroud)
使用nullptr参数调用的placement-new 运算符会导致未定义的行为。
9)由标准的单对象放置 new 表达式调用。标准库实现不执行任何操作并返回未修改的 ptr。如果通过放置 new 表达式调用此函数并且 ptr 是空指针,则行为未定义。
我现在的问题是:建议的可能实现实际上有效吗?一方面我认为不,因为涉及一个表现出未定义行为的表达式。另一方面,我认为是的,因为这个表达式出现在未评估的上下文中,因此可能不需要具有明确定义的行为(?),只需要在语法上有效。但我无法为其中一个找到明确的证据。
第二个问题:如果事实证明后者是真的,那么为什么这种新的布局满足标准要求的T t;必须是良构的?对我来说,这看起来像是一个奇怪的黑客,因为简单和复合需求都没有提供T t;精确需求的可能性。但为什么这样做呢?
目前,我已经使用 C++20约束和概念实现了分配器概念(指的是Boost 提案):
#include <concepts>
#include <iterator>
template <class A>
concept allocator =
std::copy_constructible<A> &&
std::equality_comparable<A> &&
requires(A a) {
{ a.allocate(0) } -> std::regular;
{ a.allocate(0) } -> std::constructible_from<std::nullptr_t>;
{ a.allocate(0) } -> std::equality_comparable_with<std::nullptr_t>;
{ a.allocate(0) } -> std::random_access_iterator;
{ *a.allocate(0) } -> std::same_as<typename A::value_type&>;
};
Run Code Online (Sandbox Code Playgroud)
您可以看到同一个函数有多个return-type-requirementallocate。有没有办法将它们组合成一个单一的返回类型要求,如下所示?
{ a.allocate(0) } -> std::regular &&
std::constructible_from<std::nullptr_t> &&
std::equality_comparable_with<std::nullptr_t> &&
std::random_access_iterator;
Run Code Online (Sandbox Code Playgroud) 很多文章都给出了这样的例子:
template<typename T>
concept Equal = requires(T a, T b) {
{ a == b } -> std::same_as<bool>;
};
Run Code Online (Sandbox Code Playgroud)
如果我写:
template<typename T>
concept Equal = requires(T a) {
{ a == a } -> std::same_as<bool>;
};
Run Code Online (Sandbox Code Playgroud)
如果不是,为什么语法是这样设计的?为什么他们要我声明这些变量,如a或b?
为什么我需要多个相同类型的变量?为什么我什至需要变量?
template<typename T>
concept Equal = requires {
{ declval<const T&>() == declval<const T&>() }
-> std::same_as<bool>;
};
Run Code Online (Sandbox Code Playgroud)