小编康桓瑋*_*康桓瑋的帖子

C++20 std::ranges::sort 应该不需要支持 std::vector<bool> 吗?

我注意到std::ranges::sort无法排序std::vector<bool>

<source>:6:51: error: no match for call to '(const std::ranges::__sort_fn) (std::vector<bool, std::allocator<bool> >)'
6 |   std::ranges::sort(std::vector{false, true, true});
  |   
Run Code Online (Sandbox Code Playgroud)

这是允许的吗?我们是否需要专门化std::ranges::sortfor std::vector<bool>?是否有关于委员会如何考虑这一点的任何信息?

c++ stdvector c++20 std-ranges

10
推荐指数
1
解决办法
510
查看次数

Requires-clause 出现在模板模板参数之后:这是合法的语法吗?

最近意外发现gcc和msvc接受如下代码(注意template-list中的requires-clause):

#include <vector>

template <template <class> requires true class>
void f() {}

int main() {
  f<std::vector>();
}
Run Code Online (Sandbox Code Playgroud)

和 clang拒绝它的语法:

<source>:3:28: error: template template parameter requires 'class' after the parameter list
template <template <class> requires true class>
                           ^
Run Code Online (Sandbox Code Playgroud)

我应该信任哪个编译器?这段代码在语法上有效吗?

c++ templates language-lawyer c++-concepts c++20

10
推荐指数
1
解决办法
186
查看次数

为什么 C++23 范围适配器要求可调用对象是可复制构造的?

一些范围适配器,例如filter_\xc2\xadview,take_\xc2\xadwhile_\xc2\xadviewtransform_view使用std::optional\ 的同类copyable-box来存储可调用对象:

\n
template<input_\xc2\xadrange V, copy_\xc2\xadconstructible F>\nclass transform_view : public view_interface<transform_view<V, F>> {\n private:\n  V base_ = V();\n  copyable-box<F> fun_;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

这要求可调用对象Fcopy_\xc2\xadconstructible,这也阻止我们将捕获仅移动对象的可调用对象传递给transform_viewGodbolt):

\n
#include <ranges>\n#include <memory>\n\nstruct MoveOnlyFun {\n  std::unique_ptr<int> x;\n  MoveOnlyFun(int x) : x(std::make_unique<int>(x)) { } \n  int operator()(int y) const { return *x + y; }\n};\n\nint main() {\n  auto r = std::views::iota(0, 5)\n         | std::views::transform(MoveOnlyFun(1));\n}\n
Run Code Online (Sandbox Code Playgroud)\n

既然view不是必需的copy_constructible,为什么我们要求可调用的呢 …

c++ c++20 std-ranges c++23

10
推荐指数
1
解决办法
617
查看次数

如何在 c++20 约束算法中投影 std::tuple

假设我们有一个 s 数组std::pair

using Particle = std::pair<std::string, double>;
Particle particles[] {{"Electron", 0.511}, {"Muon", 105.66}, {"Tau", 1776.86}};
Run Code Online (Sandbox Code Playgroud)

我们可以使用具有不同投影函数的C++20范围算法来根据不同的数据成员对它们进行排序:

ranges::sort(particles, {}, &Particle::first);
ranges::sort(particles, {}, &Particle::second);
Run Code Online (Sandbox Code Playgroud)

这看起来非常干净。但是当我将Particle的数据类型移至std::tuple

using Particle = std::tuple<std::string, double>;
Run Code Online (Sandbox Code Playgroud)

我不能再使用相同的投影度量,因为std::tuple没有firstsecond没有成员。或者,只需传递 lambda 即可正常工作:

ranges::sort(particles, {}, [](const auto& t) { return std::get<0>(t); });
ranges::sort(particles, {}, [](const auto& t) { return std::get<1>(t); });
 
Run Code Online (Sandbox Code Playgroud)

但是有没有更简洁的项目方法可以做到这一点?

ranges::sort(particles, {}, &std::get<0>); 
Run Code Online (Sandbox Code Playgroud)

c++ range-v3 c++20

9
推荐指数
1
解决办法
671
查看次数

为什么 std::common_iterator 只是 std::forward_iterator?

C++20 引入了std::common_iterator能够将元素的非公共范围(迭代器和哨兵的类型不同)表示为公共范围(它们相同)的 a ,其概要定义为:

template<input_­or_­output_­iterator I, sentinel_­for<I> S>
    requires (!same_­as<I, S> && copyable<I>)
class common_iterator {
  // ...
 private:
  variant<I, S> v_;   // exposition only
};
Run Code Online (Sandbox Code Playgroud)

它对于与期望范围的开始和结束具有相同类型的遗留代码进行交互非常有用。

[iterators.common#common.iter.types-1.1] 中,其iterator_­concept定义为:

iterator_­concept表示forward_­iterator_­tag如果I模型 forward_­iterator;否则表示input_­iterator_­tag

为什么common_iterator最多只能是 a forward_iterator,而不能完全定义其iterator_concept基于I's iterator_category?例如,如果Irandom_asscess_iterator,则common_iterator<I, S>random_asscess_iterator,依此类推。

看来,这是因为技术上是可行的common_iterator只是使用std::variant类型为擦除IS

考虑以下(Godbolt): …

c++ iterator range-v3 c++20 std-ranges

9
推荐指数
2
解决办法
257
查看次数

在未经评估的上下文中使用概念会产生不一致的结果

考虑以下无用的概念C

template<class T>
concept C = static_cast<T>(true);
Run Code Online (Sandbox Code Playgroud)

如果我们C在未评估的上下文中传递任意类型,那么所有三个编译器都将成功编译:

struct S {};
decltype(C<S>) x = 0;
Run Code Online (Sandbox Code Playgroud)

但是如果我们在未评估的上下文中传递intC

decltype(C<int>) y = 0;
Run Code Online (Sandbox Code Playgroud)

GCC 仍然接受它,而 Clang 和 MSVC 以相同的错误消息拒绝它

<source>:2:13: error: atomic constraint must be of type 'bool' (found 'int')
Run Code Online (Sandbox Code Playgroud)

上面的代码仍然格式良好吗?我应该信任哪个编译器?

c++ language-lawyer c++-concepts c++20

9
推荐指数
1
解决办法
255
查看次数

带约束重载静态和非静态成员函数

该代码有效吗?

template<bool b>
struct s {
    void f() const {
    }
    static void f() requires b {
    }
};

void g() {
    s<true>().f();
}
Run Code Online (Sandbox Code Playgroud)

clang 说是,但 gcc 说不

<source>: In function 'void g()':
<source>:10:20: error: call of overloaded 'f()' is ambiguous
   10 |         s<true>().f();
      |         ~~~~~~~~~~~^~
<source>:3:14: note: candidate: 'void s<b>::f() const [with bool b = true]'
    3 |         void f() const {
      |              ^
<source>:5:21: note: candidate: 'static void s<b>::f() requires  b [with bool b = true]'
    5 | …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++-concepts c++20

9
推荐指数
1
解决办法
247
查看次数

应用于“const char* const&amp;”和“char* &amp;”的三元运算符的返回类型是什么?

考虑以下无用的代码片段,它在不同的编译器中给出不一致的结果(演示

\n
#include <type_traits>\n\nchar* dummy;\nconst char* const& a = dummy;\n      char*      & b = dummy;\nusing T = decltype(true ? a : b);\nstatic_assert(std::is_same<const char* const&, T>::value); // pass in Clang and MSVC:c++20\nstatic_assert(std::is_same<const char*       , T>::value); // pass in GCC   and MSVC:c++17\n
Run Code Online (Sandbox Code Playgroud)\n

GCC认为T存在const char*于C++的所有版本中,而Clang认为存在const char* const&于所有版本中;MSVC 认为Tconst char*C++17 和const char* const&C++20 下。

\n

从语言律师\xe2\x80\x99s的角度来看,我应该相信哪个编译器?

\n

c++ conditional-operator language-lawyer

9
推荐指数
0
解决办法
223
查看次数

使用 C++20 比较 std::variant 和 int &lt;=&gt; 不是常量表达式

由于std::variant不允许在标准库中与其替代类型之一进行比较,我正在使用 C++20<=>运算符实现比较函数:

template <typename... Args, typename T>
constexpr auto operator<=>(const std::variant<Args...>& v, const T& t) {
  return std::visit([&t](const auto& u) -> std::partial_ordering {
    if constexpr (requires { u <=> t; }) return u <=> t;
    else return std::partial_ordering::unordered;
  }, v);
}
Run Code Online (Sandbox Code Playgroud)

但是当我使用自己定义的测试上述函数时std::variant

using Variant = std::variant<double, int, std::string_view>;
constexpr Variant v1{1.0};
constexpr Variant v2{1};
constexpr Variant v3{"hello"};
static_assert(v1 < 2);
// compile error
static_assert(v2 < 2);
static_assert(!(v3 > 2) && !(v3 < 2) && …
Run Code Online (Sandbox Code Playgroud)

c++ c++17 c++20 std-variant

8
推荐指数
1
解决办法
244
查看次数

std::visit 相对于 if-else 的优势

我发现 std::visit 可以按以下方式使用:

    std::visit([](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, int>)
            std::cout << "int with value " << arg << '\n';
        else if constexpr (std::is_same_v<T, std::string>)
            std::cout << "std::string with value " << std::quoted(arg) << '\n';
        else 
            static_assert(always_false_v<T>, "non-exhaustive visitor!");
    }, v);
Run Code Online (Sandbox Code Playgroud)

但相反,我想我也可以使用

    if(auto x = std::get_if<int>(&v))
        std::cout << " is int " << *x << std::endl;
    else if(auto x = std::get_if<std::string>(&v))
        std::cout << " is String " << *x << std::endl;
    else
        std::cout << "non-exhaustive visitor!" …
Run Code Online (Sandbox Code Playgroud)

c++ variant c++17

8
推荐指数
1
解决办法
2418
查看次数