考虑以下代码:
std::map<int, int> m;
int &ref = m[0];
int *ptr = &m[0];
m.insert({1,2});
std::cout << ref; // #1
std::cout << *ptr; // #2
Run Code Online (Sandbox Code Playgroud)
对于像 这样的关联容器std::map,标准说:
insert 和 emplace 成员不应影响迭代器的有效性和对容器的引用,...
这意味着#1绝对没问题。但是,我不太确定#2。
十多年前,这个问题已经被提出和回答。
接受的答案说#2在技术上是不允许的,但在实践中会起作用。
共识答案(赞成票数是接受的答案的两倍多)说#2是可以的,简单地说,上述标准引用暗示指针也没有失效。
这个问题至少还有六个相对较新的副本,其中大多数都有答案,并且所有人都说没问题#2,通常是引用上面相同的标准文本。
我不认为这是正确的。据我了解,引用不是指针,一个不能替代另一个,无论它们是否相互实现。作为对比,下面是标准说有关指称在无序关联容器元素,在换汤不换药的有效性:
重新散列使迭代器无效,...,但不会使对元素的指针或引用无效。
这明确地保证了指针的有效性,表明引用的有效性并不自动暗示它。
那么语言说#2可以吗?它是由 的有效性所暗示的#1吗?
考虑这个代码:
using func = int (*)(int, int);
template<func F>
void do_something(int first, int second) {}
int something(int first, int second) { return 42; }
void f()
{
constexpr auto function = something;
do_something<function>(10, 20);
}
Run Code Online (Sandbox Code Playgroud)
它是用 C++17 标准兼容编译器编译和运行的,但它在 C++11 标准下失败:
error: no matching function for call to ‘do_something<function>(int, int)’
17 | do_something<function>(10, 20);
Run Code Online (Sandbox Code Playgroud)
C++11 非类型模板参数和 C++17 非类型模板参数有什么区别?在 §14.1.4 [temp.param][n3690] 中:
非类型模板参数应具有以下(可选 cv 限定的)类型之一:
— 整数或枚举类型,
— 指向对象或函数的指针,— 指向对象的
左值引用或指向函数的左值引用,
— 指向成员,
——std::nullptr_t。
在 §17.1.4 [temp.param][n4713] 中:
非类型模板参数应具有以下(可选 cv 限定的)类型之一:
(4.1) …
为了填充std::vector<struct_name>from std::cin,我通常写如下代码:
struct point{
int x, y;
};
int main()
{
std::size_t n;
std::cin>>n;
std::vector<point> vec(n);
for (auto& p:vec)
std::cin>>p.x>>p.y;
//...
}
Run Code Online (Sandbox Code Playgroud)
但是今天我发现了另一种使用默认构造函数的方法:
struct point{
int x, y;
point(){
std::cin>>x>>y;
}
};
int main()
{
std::size_t n;
std::cin>>n;
std::vector<point> vec(n);
//...
}
Run Code Online (Sandbox Code Playgroud)
问题:
我对根据 C++11(和更新的)标准的行为感兴趣
template <typename T, void (*)(T), typename = void>
struct S;
template <typename T, void (*f)(T)>
struct S<T, f, void> {};
S<int const, nullptr> s;
Run Code Online (Sandbox Code Playgroud)
在 GCC 的所有版本中,在所有语言版本中,实例化S时s都会选择的特化。
在所有版本的 Clang 中,但仅从 C++17 开始,在实例化s.
我认为值得注意的一些要点是,如果实例化结束<int, nullptr>,则永远不会选择主要参数,即不再是第一个参数int const。此外,如果第二个参数中的函数指针的签名不包含T作为参数,即如果第二个参数是T (*)()、 或void (*)(),则永远不会选择主参数。
如果此代码不是 IFNDR,那么哪个编译器是正确的?C++17 语言修订版中是否有一些重大变化?
我正在 Visual Studio Code 上处理ipynb文件。(与 Github Copilot 一起)
我认为当我在代码块中按下按键时,它会提供选项卡或Copilot 自动完成功能。Tab
但它没有,并让我出了代码块 - 就像我Tab在网页中使用时一样。
我检查了键盘快捷键设置,但我得到的只是以下内容:
Emmet: Expand Abbreviation
accptSelectedSuggestion
editor.action.inlineSuggest.commit
insertBestCompletion
insertNextSuggestion
insertSnippet
jumpToNextSnippetPlaceholder
tab
Run Code Online (Sandbox Code Playgroud)
我不知道如何解决这个问题。如何防止Tab将我从代码块中弹出?
keyboard-shortcuts visual-studio-code jupyter-notebook github-copilot
假设我有一个将数据存储在地图中的自定义容器类:
class Container
{
public:
void add(int key, std::string value) { _data.emplace(key, std::move(value)); }
private:
std::map<int, std::string> _data;
};
Run Code Online (Sandbox Code Playgroud)
我想提供一个接口来访问地图的值(而不是键)。范围库提供了std::views::values地图值的范围:
auto values() { return std::views::values(_data); }
Run Code Online (Sandbox Code Playgroud)
用法:
Container c;
c.add(1, "a");
c.add(3, "b");
c.add(2, "c");
for (auto &value : c.values())
std::cout << value << " "; // Prints "a c b"
Run Code Online (Sandbox Code Playgroud)
但由于我想将我的类视为一个容器,所以我想要拥有begin()和end()迭代器。我可以这样做吗?
auto begin() { return std::ranges::begin(values()); }
auto end() { return std::ranges::end(values()); }
Run Code Online (Sandbox Code Playgroud)
在这里,我调用values()以获取映射值的范围,并获取到范围开头的迭代器(或哨兵结束迭代器)。但范围本身超出范围并被破坏。迭代器本身仍然有效吗?
从这个例子来看,迭代器似乎是有效的。std::views:values但是,无论是针对具体观点还是针对一般观点,标准是否保证了这一点?
以下程序在 GCC 和 Clang 中编译时不会发出警告,并产生预期的输出:
#include <initializer_list>
#include <iostream>
constexpr std::initializer_list<std::initializer_list<const char*>> list = {
{"a", "b", "c"},
{"d"}
};
int main() {
for (const auto& outer: list) {
std::cout << "level:\n";
for (const auto& inner: outer) {
std::cout << " " << inner << "\n";
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,使用 MSVC,该程序根本不会产生任何输出。
根据 C++ 标准,该程序有效吗?这是 MSVC 中的错误吗?如果这不是有效的 C++ 那么为什么 GCC 或 Clang 没有发出警告?有没有更好的方法来创建constexpr内部列表没有固定大小的嵌套列表?
这个问题的主要目的是提请社区注意 libstdc++ 范围不适用于 clang:https ://bugs.llvm.org/show_bug.cgi ? id = 46746
Avi Kivity 建议这是一个 gcc 错误:https ://gcc.gnu.org/bugzilla/show_bug.cgi?id=97120
但随后他也暗示这是一个叮当声错误:https ://bugs.llvm.org/show_bug.cgi ? id = 47509
Rafael Ávila de Espíndola 将问题归结为以下代码,该代码使用 gcc 编译,但不使用 clang:
template <typename _Tp>
concept __member_begin = requires(_Tp __t) {
{__t.begin()};
};
template <typename _Tp>
concept nothing = requires(_Tp __t) {
{42};
};
template <typename _Tp>
requires __member_begin<_Tp> void __ranges_begin() {}
template <typename _Derived>
struct view_interface {
void foo() requires __member_begin<_Derived> {}
void bar() requires nothing<decltype(__ranges_begin<_Derived>())> {}
};
struct …Run Code Online (Sandbox Code Playgroud) 在下面的示例中, structS继承自两个函数对象A,B每个对象都有自己的operator (),然后声明using A::operator()从 中获取运算符A:
using A = decltype([](int){ return 1; });
using B = decltype([](){ return 2; });
struct S : A, B {
using A::operator();
};
int main() {
S s;
static_assert( s() == 2 ); // passes in GCC and Clang, but why?
}
Run Code Online (Sandbox Code Playgroud)
正如我所料,这段代码被 MSVC 拒绝并出现错误:
error C2064: term does not evaluate to a function taking 0 arguments
Run Code Online (Sandbox Code Playgroud)
因为A::operator(int)确实需要 1 个参数,因此B::operator() …
c++ lambda operator-overloading multiple-inheritance language-lawyer
init当arg 的类型与您正在累积的包含类型不匹配时,是否有任何方法可以收到 std::accumulate 警告?例如,在此示例中,我们在迭代 64 位整数向量时不应累积 32 位值。但是很容易只传入 0 而忘记传递 0LL。有什么办法可以得到警告吗?-Wall -Wextra -Wconversion似乎没有帮助。我还尝试寻找可能有效的 clang tidy 检查,但也没有找到任何东西。
std::vector<long long> a = {10000000000, 10000000000};
cout << std::accumulate(a.begin(), a.end(), 0) << "\n"; // overflows
cout << std::accumulate(a.begin(), a.end(), 0LL) << "\n"; // prints 20000000000
Run Code Online (Sandbox Code Playgroud) c++ ×9
std-ranges ×2
c++-concepts ×1
c++11 ×1
c++17 ×1
c++20 ×1
clang-tidy ×1
lambda ×1
non-type ×1
pointers ×1
reference ×1
templates ×1
warnings ×1