小编Cur*_*ous的帖子

为什么std :: list :: reverse有O(n)复杂度?

为什么std::listC++标准库中的类的反向函数具有线性运行时?我认为对于双向链表,反向函数应该是O(1).

反转双向链表应该只涉及切换头指针和尾指针.

c++ stl linked-list c++11

189
推荐指数
4
解决办法
8822
查看次数

为什么编译器没有给出模糊的引用错误?

参考以下代码

#include <iostream>
#include <tuple>
#include <string>
#include <type_traits>

using std::cout;
using std::endl;
using std::string;

template <typename... Args>
void bar(Args&&...) {}

int change(const string&) { return 1; }
double change(int) { return 1.0; }

int main() {
    // bar(1, 2.0, static_cast<int(*)(const string&)>(&change));
    bar(1, 2.0, &change);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我理解上面代码中的错误是对change函数的引用是不明确的(这就是注释行的工作原理),但是为什么编译器会给出这个错误消息呢?

test.cpp:17:5: error: no matching function for call to 'bar'
    bar(1, 2.0, &change);
    ^~~
test.cpp:11:6: note: candidate function not viable: requires 2 arguments, but 3 were
      provided
void bar(Args&&...) {} …
Run Code Online (Sandbox Code Playgroud)

c++ gcc templates clang c++11

24
推荐指数
1
解决办法
1380
查看次数

为什么使用std :: forward <T>而不是static_cast <T &&>

当给出以下结构的代码时

template <typename... Args>
void foo(Args&&... args) { ... }
Run Code Online (Sandbox Code Playgroud)

我经常static_cast<Args&&>在函数中看到库代码用于参数转发.通常,对此的理由是使用static_cast避免不必要的模板实例化.

鉴于语言的参考折叠和模板扣除规则.我们得到了完美的转发,static_cast<Args&&>这个声明的证据如下(在误差范围内,我希望答案会启发)

  • 当给出rvalue引用时(或者为了完整性 - 没有像本示例中那样的引用限定条件),这会以这样的方式折叠引用,即结果是rvalue.使用的规则是&& &&- > &&(1上面的规则)
  • 当给定左值引用时,这会以这样的方式折叠引用,即结果是左值.这里使用的规则是& &&- > &(2上面的规则)

这基本上foo()bar()在上面的例子中转发参数.这也是你在std::forward<Args>这里使用时会得到的行为.


问题 -为什么要std::forward在这些背景下使用?避免额外的实例化是否有理由违反惯例?

Howard Hinnant的论文n2951规定了6个约束,在这些约束条件下,任何实现都std::forward应该"正确".这些曾经是

  1. 应该将左值作为左值转发
  2. 应该将右值作为右值转发
  3. 不应该将右值作为左值转发
  4. 应该将更少的cv限定表达式转发给更多cv限定的表达式
  5. 应该将派生类型的表达式转发为可访问的,明确的基类型
  6. 不应转发任意类型的转换

(1)和(2)证明与static_cast<Args&&>上述方法一起正常工作.(3) - (6)这里不适用,因为在推导的上下文中调用函数时,这些都不会发生.


注意:我个人更喜欢使用std::forward,但我的理由纯粹是我更喜欢坚持惯例.

c++ templates forwarding rvalue-reference c++17

23
推荐指数
3
解决办法
1429
查看次数

C ++ 20中协程的机制是什么?

我试图阅读有关在调用,暂停,恢复和终止协程函数时调用的操作顺序的文档(功能部件本身的cppreference和标准文档)。该文档深入概述了各种扩展点,这些扩展点允许库开发人员使用库组件自定义协程的行为。从高级的角度来看,这种语言功能似乎是经过深思熟虑的。

不幸的是,我在遵循协程执行机制方面确实很难,而且作为图书馆开发人员,我如何使用各种扩展点来定制所述协程的执行。甚至从哪里开始。

我不完全了解的新定制点集中包含以下功能:

  • initial_suspend()
  • return_void()
  • return_value()
  • await_ready()
  • await_suspend()
  • await_resume()
  • final_suspend()
  • unhandled_exception()

有人可以在高级伪代码中描述运行用户协程时编译器生成的代码吗?在抽象的层面,我想弄清楚的时候功能,如await_suspendawait_resumeawait_readyawait_transformreturn_value,等叫,他们所服务的目的是什么,我怎么可以用它们来写协同程序库。


不确定这是否是题外话,但是这里的一些入门资源对于整个社区来说都是非常有用的。像在cppcoro中一样四处搜寻并深入研究库实现并不能帮助我克服最初的障碍:(

c++ asynchronous coroutine c++20 c++-coroutine

21
推荐指数
1
解决办法
582
查看次数

可以在多态lambda中使用结构化绑定语法

结构化绑定使得它更加干净和可读,以迭代通过具有基于如下循环的范围的映射

for (auto [key, value] : map) {
    cout << key << " : " << value << endl;
}
Run Code Online (Sandbox Code Playgroud)

但是结构化绑定可以在lambda表达式中使用,如下所示吗?

std::for_each(map.begin(), map.end(), [](auto [key, value]) {
    cout << key << " : " << value << endl;
});
Run Code Online (Sandbox Code Playgroud)

从它看起来上面的代码不适用于我在这里找到的在线C++编译器https://wandbox.org/permlink/sS6r7JZTB3G3hr78.

如果它不起作用那么是否有充分的理由不支持上述内容?或者它只是尚未提出的东西?模板只会在使用时被实例化,因此结构化绑定的"解除绑定"过程可能发生在请求实例化的地方(即调用函数时)

c++ lambda c++17

19
推荐指数
2
解决办法
1522
查看次数

复制省略是否适用于结构化绑定

强制复制省略是否适用于通过结构化绑定进行分解?以下哪种情况适用于?

// one
auto [one, two] = std::array<SomeClass>{SomeClass{1}, SomeClass{2}};

// two
auto [one, two] = std::make_tuple(SomeClass{1}, SomeClass{2});

// three
struct Something { SomeClass one, two; };
auto [one, two] = Something{};    
Run Code Online (Sandbox Code Playgroud)

我怀疑只有第三种情况允许复制省略,因为前两个会被"分解"通过std::get<>std::tuple_size<>std::get<>当参数是右值返回xvalues

标准的引用也很好!

c++ rvalue copy-elision c++17 structured-bindings

16
推荐指数
1
解决办法
827
查看次数

为什么ADL无法使用std :: get解析为正确的函数

我正在尝试编写一个模板函数,该函数使用已解析的ADL get来获取struct/range(tuple-esque)的成员.

#include <iostream>
#include <utility>
#include <tuple>

int main() {
    auto tup = std::make_tuple(1, 2);
    std::cout << get<0>(tup) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我这样做是因为结构化绑定提案(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf§11.5.3 )说的是如何get习惯的从结构中获取元素.它表示非成员get用于从结构中获取元素.

我假设上面的代码会编译,因为ADL会导致getstd命名空间中查找函数(因为它的参数是类型std::tuple<int, int>,在其中std),在那里可以找到它.但是,我收到了一个错误.有人可以在这里解释正确的方法,以及为什么上面的代码不起作用?在这种情况下如何强制ADL发生?

c++ tuples c++17 structured-bindings

15
推荐指数
2
解决办法
461
查看次数

与SFINAE中的硬错误混淆

关于以下代码(https://wandbox.org/permlink/nhx4pheijpTF1ohf为方便起见,下面转载)

#include <type_traits>
#include <utility>

namespace foo_name {
template <typename T>
void foo();
template <>
void foo<int>();

template <typename T>
struct c_size;
template <>
struct c_size<int> : public std::integral_constant<int, 1> {};
} // namespace foo_name

template <typename Type>
class Foo {
public:
    template <typename T>
    static decltype(auto) impl(T&& t) {
        using foo_name::foo;
        return foo(std::forward<T>(t));
    }
};

class Something {};

template <typename Type, typename T = std::decay_t<Type>>
using EnableIfHasFoo = std::void_t<
    decltype(Foo<T>::impl(std::declval<T>())),
    decltype(foo_name::c_size<Type>::value)>;

template <typename Type, typename = std::void_t<>> …
Run Code Online (Sandbox Code Playgroud)

c++ templates sfinae c++17

15
推荐指数
1
解决办法
366
查看次数

为什么std :: forward有两个重载?

鉴于以下参考折叠规则

  • T& & - > T&
  • T&& & - > T&
  • T& && - > T&
  • T&& && - > T&&

第三和第四条规则意味着T(ref qualifer) &&身份转变,即T&停留在T&T&&保持在T&&.为什么我们有两个重载std::forward?以下定义无法满足所有目的吗?

template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& forward(const typename std::remove_reference<T>::type& val) {
    return static_cast<T&&>(const_cast<T&&>(val));
}
Run Code Online (Sandbox Code Playgroud)

这里服务的唯一目的const std::remove_reference<T>&是不复制.并且enable_if有助于确保仅在非const值上调用该函数.我不完全确定是否const_cast需要它,因为它不是引用本身的const.

由于forward总是使用显式模板参数调用,因此我们需要考虑两种情况:

  1. forward<Type&>(val)这里Tin 的类型forward将是T&,因此返回类型将是身份转换T&
  2. forward<Type&&>(val)这里Tin 的类型forward将是T&& …

c++ reference rvalue perfect-forwarding c++11

13
推荐指数
1
解决办法
772
查看次数

非预先声明的函数调用适用于类类型,但不适用于基本类型

在以下代码中

template <typename T>
void foo(T) {
    bar(T{});
}

class Something {};
void bar(Something) {}

int main() {
    foo(Something{});
}
Run Code Online (Sandbox Code Playgroud)

(https://wandbox.org/permlink/l2hxdZofLjZUoH4q)

当我们foo()使用Something参数调用时,一切都按预期工作,调用将调度到bar(Something)重载.

但是当我将参数更改为整数并提供bar(int)重载时,我得到一个错误

template <typename T>
void foo(T) {
    bar(T{});
}

void bar(int) {}

int main() {
    foo(int{});
}
Run Code Online (Sandbox Code Playgroud)

错误:

error: call to function 'bar' that is neither visible in the template definition nor found by argument-dependent lookup
Run Code Online (Sandbox Code Playgroud)

(https://wandbox.org/permlink/GI6wGlJYxGO4svEI)

在类的情况下,我没有bar()在命名空间中定义以及Something.这意味着我没有得到ADL.那么为什么代码适用于类类型呢?

c++ argument-dependent-lookup c++17

13
推荐指数
1
解决办法
283
查看次数