C++ 20概念的一个角落是,在某些情况下你必须编写requires requires
.例如,[expr.prim.req]/3中的这个例子:
甲需要表达也可以在使用需要子句([温度])作为写在模板参数特设约束,如下面的一个的一种方法:
Run Code Online (Sandbox Code Playgroud)template<typename T> requires requires (T x) { x + x; } T add(T a, T b) { return a + b; }
第一个需要引入requires子句,第二个需要引入requires-expression.
需要第二个requires
关键字的技术原因是什么?为什么我们不能只允许写作:
template<typename T>
requires (T x) { x + x; }
T add(T a, T b) { return a + b; }
Run Code Online (Sandbox Code Playgroud)
(注意:请不要回答那个语法requires
吧)
我想知道C++完整概念提议和模板约束之间的语义差异(例如,Dlang中出现的约束或C++ 1y的新概念 - 精简提议).
什么是能够比模板约束做的完整概念不能做到的?
在 C++20 中,我们现在能够将auto
关键字限制为仅属于特定类型。因此,如果我有一些如下所示的代码,没有任何限制:
auto something(){
return 1;
}
int main(){
const auto x = something();
return x;
}
Run Code Online (Sandbox Code Playgroud)
这里的变量x
被推导为一个int
。然而,随着 C++20 的引入,我们现在可以将 约束auto
为某种类型,如下所示:
std::integral auto something(){
return 0;
}
int main(){
const auto x = something();
return x;
}
Run Code Online (Sandbox Code Playgroud)
这不是违背了来这里的目的吗auto
?如果我真的需要一个std::integral
数据类型,我不能完全省略吗auto
?我是否完全误解了使用auto
?
我正在观看Walter Brown的CppCon2014关于模板元编程的第二部分,在此期间他讨论了他的新颖void_t<>
结构的用法.在他的演讲中,Peter Sommerlad问他一个我不太明白的问题.(链接直接转到问题,正在讨论的代码直接发生在那之前)
索默拉德问道
沃尔特,这是否意味着我们现在实际上可以实现概念精简版?
沃尔特回应了什么
哦耶!我已经完成了......它没有完全相同的语法.
我理解这个交换是关于Concepts Lite的.这种模式真的那么多才多艺吗?无论出于何种原因,我都没有看到它.有人可以解释(或描绘)这样的事情会是什么样子?这是关于enable_if
和定义特征,还是提问者指的是什么?
该void_t
模板定义如下:
template<class ...> using void_t = void;
Run Code Online (Sandbox Code Playgroud)
然后他使用它来检测类型语句是否格式正确,使用它来实现is_copy_assignable
类型特征:
//helper type
template<class T>
using copy_assignment_t
= decltype(declval<T&>() = declval<T const&>());
//base case template
template<class T, class=void>
struct is_copy_assignable : std::false_type {};
//SFINAE version only for types where copy_assignment_t<T> is well-formed.
template<class T>
struct is_copy_assignable<T, void_t<copy_assignment_t<T>>>
: std::is_same<copy_assignment_t<T>,T&> {};
Run Code Online (Sandbox Code Playgroud)
由于这个话题,我理解这个例子是如何工作的,但是我没有看到我们如何从这里得到像Concepts Lite这样的东西.
我正在尝试使用Concepts Lite来指定一个概念来约束具有成员函数模板的更高级的kinded类型.但是,我无法在技术规范或教程中找到一个处理概念中模板化语句的子句.
这是怎么做到的?
示例:假设我HKT
的成员函数模板具有更高的kinded类型F
:
template<class T>
struct HKT {
template<class U> // this looks like e.g. rebind in std::allocators
auto F(U) -> HKT<U>;
};
Run Code Online (Sandbox Code Playgroud)
现在我想指定一个约束这些更高级的类型的概念:
template <template <class> class HKT, class T>
concept HKTWithTemplateMemberFunctionF {
return requires(HKT<T> h) { // HKT<T> is a type, h is an object
// HKT<T> needs to have a member function template that
// returns HTK<U> where the type U is to be deduced and
// it …
Run Code Online (Sandbox Code Playgroud) 使用 C++20'sconcept
我注意到这std::unique_ptr
似乎无法满足这个std::equality_comparable_with<std::nullptr_t,...>
概念。从std::unique_ptr
的定义来看,它应该在 C++20 中实现以下内容:
template<class T1, class D1, class T2, class D2>
bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
template <class T, class D>
bool operator==(const unique_ptr<T, D>& x, std::nullptr_t) noexcept;
Run Code Online (Sandbox Code Playgroud)
这个要求应该实现对称比较nullptr
——根据我的理解,这足以满足equality_comparable_with
.
奇怪的是,这个问题似乎在所有主要编译器上都是一致的。以下代码被 Clang、GCC 和 MSVC 拒绝:
// fails on all three compilers
static_assert(std::equality_comparable_with<std::unique_ptr<int>,std::nullptr_t>);
Run Code Online (Sandbox Code Playgroud)
然而,同样的断言与std::shared_ptr
被接受:
// succeeds on all three compilers
static_assert(std::equality_comparable_with<std::shared_ptr<int>,std::nullptr_t>);
Run Code Online (Sandbox Code Playgroud)
除非我误解了什么,否则这似乎是一个错误。我的问题是这是否是三个编译器实现中的巧合错误,还是 C++20 标准中的缺陷?
注意:如果这恰好是一个缺陷,我会标记这个语言律师 …
我的一个朋友向我展示了一个带有概念的 C++20 程序,这让我感到困惑:
struct A { static constexpr bool a = true; };
template <typename T>
concept C = T::a || T::b;
template <typename T>
concept D = !!(T::a || T::b);
static_assert( C<A> );
static_assert( !D<A> );
Run Code Online (Sandbox Code Playgroud)
它被所有编译器接受:https : //gcc.godbolt.org/z/e67qKoqce
这里的概念与概念D
相同C
,唯一的区别是双重否定运算符!!
,乍一看不会改变概念值。仍然对于 struct 来说,A
这个概念C
是正确的,而这个概念D
是错误的。
你能解释一下为什么会这样吗?
我注意到大多数(如果不是所有)容器现在都需要它们的::iterator
类型LegacySomethingIterator
而不是SomethingIterator
.
例如,std::vector<>::iterator
现在需要:
iterator
LegacyRandomAccessIterator
这似乎是大多数其它容器一样,都是需要自己迭代器从去SomethingIterator
到LegacySomethingIterator
.
还有"新"要求采用旧要求的名称,例如RandomAccessIterator
,为什么这些要求被添加?在我看来,新的变种只会影响遗留的变种,没有差异.
为什么首先创建新的,他们的要求对我来说是一样的.为什么新的只是替换旧的要求而不是现在有两个不同的名称(例如RandomAccessIterator
和LegacyRandomAccessIterator
)?
在Rust中,抽象的主要工具是traits。在C ++中,有两种用于抽象的工具:抽象类和模板。为了摆脱一些使用模板的缺点(例如,硬盘读取错误消息),C ++引入的概念,这是“命名集的要求”。
这两个功能似乎非常相似:
但据我了解,也存在显着差异。例如,C ++的概念似乎定义了一组必须有效的表达式,而不是列出函数签名。但是那里有很多不同且令人困惑的信息(也许是因为概念仅出现在C ++ 20中?)。这就是为什么我想知道:C ++概念和Rust的特性之间的区别和相似之处到底是什么?
是否存在仅概念或特征提供的功能?例如,Rust的关联类型和const如何?还是用多个特征/概念来界定一个类型?