为什么std::listC++标准库中的类的反向函数具有线性运行时?我认为对于双向链表,反向函数应该是O(1).
反转双向链表应该只涉及切换头指针和尾指针.
参考以下代码
#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) 当给出以下结构的代码时
template <typename... Args>
void foo(Args&&... args) { ... }
Run Code Online (Sandbox Code Playgroud)
我经常static_cast<Args&&>在函数中看到库代码用于参数转发.通常,对此的理由是使用static_cast避免不必要的模板实例化.
鉴于语言的参考折叠和模板扣除规则.我们得到了完美的转发,static_cast<Args&&>这个声明的证据如下(在误差范围内,我希望答案会启发)
&& &&- > &&(1上面的规则)& &&- > &(2上面的规则)这基本上foo()是bar()在上面的例子中转发参数.这也是你在std::forward<Args>这里使用时会得到的行为.
问题 -为什么要std::forward在这些背景下使用?避免额外的实例化是否有理由违反惯例?
Howard Hinnant的论文n2951规定了6个约束,在这些约束条件下,任何实现都std::forward应该"正确".这些曾经是
(1)和(2)证明与static_cast<Args&&>上述方法一起正常工作.(3) - (6)这里不适用,因为在推导的上下文中调用函数时,这些都不会发生.
注意:我个人更喜欢使用std::forward,但我的理由纯粹是我更喜欢坚持惯例.
我试图阅读有关在调用,暂停,恢复和终止协程函数时调用的操作顺序的文档(功能部件本身的cppreference和标准文档)。该文档深入概述了各种扩展点,这些扩展点允许库开发人员使用库组件自定义协程的行为。从高级的角度来看,这种语言功能似乎是经过深思熟虑的。
不幸的是,我在遵循协程执行机制方面确实很难,而且作为图书馆开发人员,我如何使用各种扩展点来定制所述协程的执行。甚至从哪里开始。
我不完全了解的新定制点集中包含以下功能:
initial_suspend()return_void()return_value()await_ready()await_suspend()await_resume()final_suspend()unhandled_exception()有人可以在高级伪代码中描述运行用户协程时编译器生成的代码吗?在抽象的层面,我想弄清楚的时候功能,如await_suspend,await_resume,await_ready,await_transform,return_value,等叫,他们所服务的目的是什么,我怎么可以用它们来写协同程序库。
不确定这是否是题外话,但是这里的一些入门资源对于整个社区来说都是非常有用的。像在cppcoro中一样四处搜寻并深入研究库实现并不能帮助我克服最初的障碍:(
结构化绑定使得它更加干净和可读,以迭代通过具有基于如下循环的范围的映射
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.
如果它不起作用那么是否有充分的理由不支持上述内容?或者它只是尚未提出的东西?模板只会在使用时被实例化,因此结构化绑定的"解除绑定"过程可能发生在请求实例化的地方(即调用函数时)
强制复制省略是否适用于通过结构化绑定进行分解?以下哪种情况适用于?
// 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
标准的引用也很好!
我正在尝试编写一个模板函数,该函数使用已解析的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会导致get在std命名空间中查找函数(因为它的参数是类型std::tuple<int, int>,在其中std),在那里可以找到它.但是,我收到了一个错误.有人可以在这里解释正确的方法,以及为什么上面的代码不起作用?在这种情况下如何强制ADL发生?
关于以下代码(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) 鉴于以下参考折叠规则
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总是使用显式模板参数调用,因此我们需要考虑两种情况:
forward<Type&>(val)这里Tin 的类型forward将是T&,因此返回类型将是身份转换T&forward<Type&&>(val)这里Tin 的类型forward将是T&& …在以下代码中
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++ ×10
c++17 ×6
c++11 ×3
templates ×3
rvalue ×2
asynchronous ×1
c++20 ×1
clang ×1
copy-elision ×1
coroutine ×1
forwarding ×1
gcc ×1
lambda ×1
linked-list ×1
reference ×1
sfinae ×1
stl ×1
tuples ×1