小编cig*_*ien的帖子

引用失效保证会自动应用于指针吗?

考虑以下代码:

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吗?

c++ pointers reference language-lawyer

11
推荐指数
1
解决办法
270
查看次数

C++17 和 C++11 中的非类型模板参数有什么区别?

考虑这个代码:

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) …

c++ language-lawyer non-type c++11 c++17

11
推荐指数
1
解决办法
180
查看次数

标准是否保证了向量元素的初始化顺序?

为了填充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)

问题:

  1. 向量元素的初始化顺序是否由标准(0,1,2,n-1...)保证?
  2. (如果上一个问题的答案是正确的)第二个变体真的有两次有效吗?

我对根据 C++11(和更新的)标准的行为感兴趣

c++ language-lawyer

11
推荐指数
2
解决办法
754
查看次数

为什么 Clang 更喜欢主模板而不是 C++17 的专业化?

以下程序是从这个问题中的代码减少的:

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 语言修订版中是否有一些重大变化?

c++ templates template-specialization language-lawyer

11
推荐指数
1
解决办法
220
查看次数

Tab 不 Tab 并让我输出代码

我正在 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

11
推荐指数
1
解决办法
2997
查看次数

视图迭代器在视图的生命周期之外是否有效?

假设我有一个将数据存储在地图中的自定义容器类:

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但是,无论是针对具体观点还是针对一般观点,标准是否保证了这一点?

c++ language-lawyer c++20 std-ranges

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

constexprinitializer_list 使用 MSVC 不产生输出

以下程序在 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内部列表没有固定大小的嵌套列表?

c++ language-lawyer stdinitializerlist

11
推荐指数
1
解决办法
215
查看次数

应该急切地还是懒惰地评估 C++ 约束?

这个问题的主要目的是提请社区注意 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)

c++ language-lawyer c++-concepts std-ranges

10
推荐指数
2
解决办法
183
查看次数

选择继承运算符与 C++ 中的“using”子句相反

在下面的示例中, 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

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

std::accumulate 溢出警告

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++ warnings clang-tidy

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