上次我将 C++ 概念与 GCC 和 fconcepts 标志一起使用时,以下代码段曾经起作用
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> bool;
{ a != b } -> bool;
};
Run Code Online (Sandbox Code Playgroud)
显然,情况不再如此,复合需求之后的返回类型需求现在只能包含类型约束。如果我没记错的话,这基本上意味着使用另一个概念来满足return-type-requirement。
所以完全可读和(对于 C++ 标准)短片断变成
template <typename From, typename To>
concept convertible_to = std::is_convertible_v<From, To>;
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> convertible_to<bool>;
{ a != b …Run Code Online (Sandbox Code Playgroud) 我知道 Clang 和 GCC 或多或少是兼容的 C/C++ 编译器,只要处理好架构标志、预定义和链接正确的库之类的事情。使用一个编译器创建库并将它们与另一个编译器创建的对象链接实际上非常简单(至少在 x86 上)。
这是一个小测试项目,正是这样做的: https://gitlab.com/higaski/Interoperability
但是我想知道链接时间优化(LTO)是否可以跨编译器工作?我知道 LTO 需要某种形式的中间表示,例如 LLVM 位码或 GCC GIMPLE,但也许有一个工作流程可以同时利用它们?
我目前正在尝试了解即将到来的 std::ranges。作为练习,我想从头开始实现一个“toupper”视图,它对某些字符进行范围/视图并将其转换为大写。
将视图和一些迭代器组合在一起非常简单,我不明白如何操作符()和| 必须重载才能像其他范围一样进行组合。
这是我到目前为止想出的“toupper_fn”(遵循范围命名约定)。这几乎是 v3 范围内某些视图函数的复制/粘贴:
struct toupper_fn {
template <typename Rng>
auto operator()(Rng&& rng) const {
return toupper_view{std::forward<Rng>(rng)};
}
template <typename Rng>
friend auto operator|(Rng&& rng, toupper_fn& c)
-> decltype(c(std::forward<Rng>(rng))) {
return c(std::forward<Rng>(rng));
}
template <typename Rng>
friend auto operator|(Rng&& rng, toupper_fn const& c)
-> decltype(c(std::forward<Rng>(rng))) {
return c(std::forward<Rng>(rng));
}
template <typename Rng>
friend auto operator|(Rng&& rng, toupper_fn&& c)
-> decltype(std::move(c)(std::forward<Rng>(rng))) {
return std::move(c)(std::forward<Rng>(rng));
}
};
Run Code Online (Sandbox Code Playgroud)
问题是,对于这些定义,经典函数调用语法 (view(view...)) 和管道语法,仅当我自己的视图是链中的最后一个时才有效。
这是 godbolt 上的完整代码 ->
使用 range-v3: https: //godbolt.org/z/6RlNVC
或 …
在即将到来的 C++20 范围中,范围概念的定义如下:
template< class T >
concept range = __RangeImpl<T&>; // exposition-only definition
template< class T >
concept __RangeImpl = requires(T&& t) {
ranges::begin(std::forward<T>(t)); // equality-preserving for forward iterators
ranges::end (std::forward<T>(t));
};
template< class T >
concept __ForwardingRange = ranges::range<T> && __RangeImpl<T>;
Run Code Online (Sandbox Code Playgroud)
将其翻译成简单的英语,我会说,满足范围概念的类型的唯一要求是可以使用 range::begin 和 Ranges::end 进行调用。
但是,如果我创建一个空类型,只开始和结束范围概念的静态断言失败?
namespace ranges = std::experimental::ranges;
struct A {
void begin() {}
void end() {}
};
static_assert(ranges::range<A>);
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
我只是偶然发现了GCC和Clang在显式默认constexpr ctor和某些继承方面的以下区别...
template <typename T>
struct A {
constexpr A() = default;
T v;
};
struct B : A<int> {
constexpr B() = default;
};
Run Code Online (Sandbox Code Playgroud)
GCC立即拒绝该代码,而Clang允许实例化这两种类型的非constexpr版本。我的猜测是Clang可能是正确的,但我不确定100%...