小编Nel*_*eal的帖子

构造函数:默认和委托参数之间的区别

今天,我偶然发现了构造函数的这些标准声明std::vector:

// until C++14
explicit vector( const Allocator& alloc = Allocator() );
// since C++14
vector() : vector( Allocator() ) {}
explicit vector( const Allocator& alloc );
Run Code Online (Sandbox Code Playgroud)

在大多数标准容器中都可以看到这种变化.一个稍微不同的例子是std::set:

// until C++14
explicit set( const Compare& comp = Compare(),
              const Allocator& alloc = Allocator() );
// since C++14
set() : set( Compare() ) {}
explicit set( const Compare& comp,
              const Allocator& alloc = Allocator() );
Run Code Online (Sandbox Code Playgroud)

两种模式之间有什么区别?它们(dis)的优势是什么?
它们是否完全等效 - 编译器是否生成类似于第一个的第二个类似的东西?

c++ std c++14

20
推荐指数
1
解决办法
300
查看次数

复制elision直接基类初始化?

由于构造函数中的B基类子项目的复制构造,以下代码无法使用Gcc和Clang进行编译A:

struct B{
  B();
  B(const B&) =delete;
  };

struct A:B{
  A():B(B()){} //=> error: use of deleted function...
  };
Run Code Online (Sandbox Code Playgroud)

不过根据[class.base.init]/7:

表达式列表支撑-INIT列表MEM-初始化是根据[dcl.init]用于初始化规则用来初始化指定子对象(或者,在一个委派构造,完整的类对象的情况下)直接初始化.

因此初始化规则对于成员或直接基础是相同的.对于成员子对象,Gcc和Clang不使用已删除的复制构造函数:

struct A2:B{
  B b;
  A2():b(B()){} //=> OK the result object of B() is b
  };
Run Code Online (Sandbox Code Playgroud)

这不是Clang和Gcc的编译器错误吗?是不是B应该省略复制构造函数A()


有趣的是,即使gcc检查复制结构是否格式正确,它也会忽略此复制构造函数调用,请参阅此处的程序集

c++ language-lawyer c++17

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

std :: vector构造函数接受迭代器对

我正在制作某种容器,我想模仿一个接口std::vector.但是,我很难理解构造函数重载(4)是如何工作的.问题是它通常与重载冲突(2).

// (2)
vector(size_type count, const T& value, const Allocator& alloc = Allocator());
// (4)
template<class InputIt>
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator());
Run Code Online (Sandbox Code Playgroud)

根据cppreference,直到C++ 11:

如果InputIt是整数类型,则此构造函数与overload(2)具有相同的效果.

我理解它是如何完成的(我认为是标签调度或模板专业化),但我不知道在C++ 11中如何实现新行为:

如果InputIt满足InputIterator,则此重载仅参与重载决策,以避免与重载(2)的歧义.

这是某种SFINAE技巧吗?我不明白SFINAE如何在这里工作.而且,既然概念或不是C++ 11(也不是C++ 14)中的东西,我不知道如何为我的容器做到这一点.

因此我的问题是:它是如何在标准库中完成的(或者至少是一个猜测),我怎样才能相对容易地为我的容器做到这一点?

c++ stl c++11

7
推荐指数
1
解决办法
674
查看次数

为什么关联容器具有非常量迭代器参数的擦除重载?

C++11 更改std::vector::erase为采用 aconst_iterator而不是iterator. 同样的事情也适用于std::dequeand std::list,而std::forward_listC++11 中的 witherase_after也采用const_iterator.

相比之下,std::set::erase保留了它的iterator重载,而 C++11 只是添加了一个const_iterator。同样的事情也适用于所有关联容器:std::mapstd::multisetstd::multimapall 保留了 C++11 之前的iterator重载std::unordered_setstd::unordered_map而 、std::unordered_multiset、 和std::unordered_multimapall 则通过iteratorconst_iterator重载引入。

事实上,对于所有四个集合类,iteratorconst_iterator很可能是同一类型

那么为什么会出现这种差异呢?除了与非关联容器不一致之外,还与范围擦除重载不一致,这些重载都在 C++11 中更改为采用一对const_iterators 而不是一对iterators。由于 aniterator必须可转换为 a const_iterator,因此无需将所有四种可能的参数组合用于范围擦除。同样,单值擦除不需要“所有两种组合”,那么为什么要保留重载呢iterator

c++ iterator stl erase c++11

6
推荐指数
1
解决办法
98
查看次数

具有非平凡构造函数的"不可变"结构

我一直在寻找一种方法来使用非平凡的构造函数声明某种不可变类型.我目前的目标是从文件中读取数据以构造对象,以便随后不能对其进行修改.它类似于POD类型,除了我需要文件中的数据,因此构造函数必须读取它.

通过我的研究和实验,我想到了三种方法.基本上,我的问题是:有没有更好的方法来做我想要的?

在下面的例子中,我将std::cin用作文件的替代品.首先,这是明显的类与getter的方式:

class A {
public:
    A() { std::cin >> m_i; }
    int i() { return m_i; }

private:
    int m_i;
};
Run Code Online (Sandbox Code Playgroud)

事实上,我在使用这个解决方案时遇到了麻烦,仅仅是因为吸气剂.毕竟,它是一种POD类型,我希望它与公共数据成员一样对待.另外,我只是不喜欢吸气剂.所以我尝试了一些const-ness并调整构造函数:

struct B {
    B() : B(B::fromFile()) {
    }

    B(int i) : i(i) {
    }

    const int i;

private:
    static B fromFile() {
        int i;
        std::cin >> i;
        return B(i);
    }
};
Run Code Online (Sandbox Code Playgroud)

这里有几个问题.我需要委托一个静态方法,因为我不能直接在构造函数的初始化列表中获取成员的值.这个方法需要创建每个成员的副本(这里只是它i)并单独初始化它们,以便它可以在使用复制构造函数最终构造初始对象之前将它们传递给另一个构造函数.此外,由于新的构造函数和静态方法,它需要更多的代码行.

所以,这种方法似乎注定要失败.然后我意识到,我真正想要的是该类/结构的每个实例const.但是,据我所知,没有办法强迫用户const每次都使用该关键字.所以,我想到了using别名声明.有点像标准库所做的那样const_reference(几乎每个容器).只有在这种情况下,它将是另一种方式:类型将被调用NonConstType,或者说MutableType,并且别名将被声明如下:

using Type = const MutableType; …
Run Code Online (Sandbox Code Playgroud)

c++ c++11

5
推荐指数
1
解决办法
770
查看次数

自定义枚举底层类型

我可以定义一个类型作为枚举的基础类型吗?像这样的东西:

struct S {
    S(int i) : value(i) {}
    operator int() { return value; }

    int value;
};

enum E : S {
    A, B, C
};
Run Code Online (Sandbox Code Playgroud)

错误消息告诉我S必须是整数类型.我试图std::is_integral像下面那样专注,但似乎在这种情况下,"整数类型"实际上意味着其中一种基本类型.

namespace std {
    template<>
    struct is_integral<S> : public true_type {};
}
Run Code Online (Sandbox Code Playgroud)

那么,使用任何版本的C++,有没有办法让自定义类型作为整数类型传递?

c++ enums

5
推荐指数
1
解决办法
1276
查看次数

using-declaration和instantiation中的默认模板参数

编辑:
显然,GCC允许实例化没有参数列表的类模板(当参数默认时),这是不合规的(Clang是合规的).
我猜测要求括号的原因(即使参数列表为空)是明确表示它是模板实例化,而不是实际类型.
因此,我正在将我原来的问题转向类模板和函数模板案例之间的差异:为什么在第二个片段中允许调用无括号,与第一个片段中A的实例化相反?为什么不允许b?


原始:
只有默认参数的类模板可以在没有任何参数列表的情况下实例化(参见下面的A).
但是,如果通过using-declaration定义该类模板的别名作为具有相同默认参数的模板(参见下面的B),则其实例化需要参数列表(可能为空).
同样,将类模板的别名定义为实际类型(参见下面的C)需要一个参数列表(同样可能为空).
这背后有原因吗?

template<int i = 1>
struct A {
    operator int() { return i; }
};

template<int i = 2>
using B = A<i>;

// using C = A;    <-- error: missing template arguments after 'A'
using C = A<>;

int main() {
    A a; // Edit: Actually should require brackets: A<> a;
    // B b;    <-- error: missing template arguments before 'b'
    B<> b;
    C c;
}
Run Code Online (Sandbox Code Playgroud)

住在Coliru

我尝试使用函数模板而不是类模板构建类似的场景,并且在最后一种情况(C)中存在细微差别:如果在定义中指定了返回类型,则不需要参数列表a.我想我理解为什么,但我会欢迎一些见解.否则,两种情况都类似于类模板.

template<int …
Run Code Online (Sandbox Code Playgroud)

c++ templates language-lawyer c++17

4
推荐指数
1
解决办法
261
查看次数

从32位数据类型中有效地丢弃2位

假设您有32位数据类型:

// The letters are just to identify the position of each bit later in the post
abcdefgh ijklmnop qrstuvwx yzABCDEF
Run Code Online (Sandbox Code Playgroud)

我正在记录在某些位置"丢弃"位的最有效方法,其中丢弃意味着"移除"给定位,并移动以下位以填充其位置.

示例:假设我想删除"a"和"q"位.然后结果应该看起来像:

bcdefghi jklmnopr stuvwxyz ABCDEF00
Run Code Online (Sandbox Code Playgroud)

要么

00bcdefg hijklmno prstuvwx yzABCDEF
Run Code Online (Sandbox Code Playgroud)

这两种结果都是可以接受的.

在我的具体情况下,我也可以施加以下约束:

  • 在我的情况下,下跌的位置是静态的; 即我将始终需要完全删除第1和第16位("a"和"q")
  • 要删除的位("a"和"q")始终为0
  • 最终填充数据的位(操作后向左或向右的"00")无关紧要 - 即,如果它们实际为0或1则无关紧要

目前我正在使用这样的方法(伪代码):

// called with number = abcdefgh ijklmnop qrstuvwx yzABCDEF
auto drop_bits_1_16(unsigned int number)
{
    number = number << 1; // number becomes: bcdefghi jklmnopq rstuvwxy zABCDEF0
    unsigned number1 = number & 0xFFFE0000;  // number1 comes: bcdefghi jklmnop0 00000000 00000000 …
Run Code Online (Sandbox Code Playgroud)

c++ algorithm bit-manipulation

4
推荐指数
1
解决办法
178
查看次数

SDL_WINDOW_INPUT_FOCUS和SDL_WINDOW_MOUSE_FOCUS

什么是SDL_WindowFlags SDL_WINDOW_INPUT_FOCUS和SDL_WINDOW_MOUSE_FOCUS用于?

如果我没有弄错,SDL_WINDOW_INPUT_GRABBED指示哪个窗口正在接收输入,如果有的话.但我根本看不出其他两个标志是什么意思.我检查了SDL_video.h以查看是否可以获得更多信息,但我读到的内容没有帮助:

SDL_WINDOW_INPUT_GRABBED = 0x00000100,      /**< window has grabbed input focus */
SDL_WINDOW_INPUT_FOCUS = 0x00000200,        /**< window has input focus */
SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */
Run Code Online (Sandbox Code Playgroud)

我没有看到"窗口抓住输入焦点"和"indow有输入焦点"之间的区别.
INPUT_FOCUS仅用于键盘输入,MOUSE_FOCUS用于鼠标输入吗?在这种情况下,为什么INPUT_GRABBED不是这两者的组合?

此外,是否可以有一个鼠标焦点的窗口和另一个具有"输入"焦点的窗口(无论"输入"在这里意味着什么,除了"鼠标"),或类似的东西?

flags sdl-2

3
推荐指数
1
解决办法
1562
查看次数

不会使迭代器(和指针)失效的容器

我目前正在寻找提供一些插入(插入或 push_back)和一些删除(擦除,pop_back 不够)方法的容器,并且在调用这两个方法时不会使迭代器或指针无效。

更清楚的是,我想要一组元素,我可以在其中添加元素(我不在乎在哪里),以及在哪里可以删除任何元素(所以我很在乎在哪里)。此外,我会有指向特定元素的外部指针,并且如果我从集合中添加或删除元素,我希望它们保持有效。

据我所知,有两个标准容器可以满足我的需求:setlist. 但是,一般来说,我不喜欢将这样的容器用于这种简单的需求。由于 alist在内部涉及指针并且不提供对其元素的随机访问,我认为这不是一个好的选择。Aset对其元素进行随机访问,但也涉及指针,并且随机访问本身不是在恒定时间内完成的。我认为 aset将是比 a 更好的解决方案list,但我已经考虑过其他事情。

当一个元素被移除时,一个不尝试保持元素连续的简单向量呢?当移除此容器中间的元素时,其位置将为空,并且不会发生任何其他事情。这样,任何迭代器或指针都不会失效。另外,在添加元素时,容器会搜索一个空位置,push_back如果没有这样的孔,则使用简单的。

显然,由于push_back可以vector使用 a使迭代器无效,我将使用 adeque作为实现的基础。我还会使用某种堆栈来跟踪删除元素的漏洞。这样,除了满足我的无失效需求之外,添加、删除和访问元素将在恒定时间内完成。

然而,仍然存在一个问题:当迭代这个容器或简单地通过索引访问一个元素时,我们需要考虑这些漏洞。这就是问题开始超越优势的地方。

因此我的问题是:您如何看待我对那个容器的想法?更重要的是,你会用什么来解决我原来的问题, a set, alist还是别的什么?另外,如果您对最后一个问题(迭代我的容器)有一个漂亮而干净的解决方案,请随时向我展示。

c++ containers c++11

3
推荐指数
1
解决办法
949
查看次数

SDL_Init 到底做了什么?

所以,我大约一年前开始使用 SDL,我只是认为 SDL_Init 初始化了 SDL 的子系统(如此处所写: https: //wiki.libsdl.org/SDL_Init),并且我必须在执行其他操作之前调用它。但今天,我意识到在一个相当大的项目中,我只是忘记调用它,而且我从来没有遇到任何问题:一切都很完美。所以我只是想知道它的作用,因为我显然不需要它来使用该库?

sdl sdl-2

3
推荐指数
1
解决办法
4081
查看次数

为什么 C++11 中 const 成员函数可以修改对象的可变数据成员?

成员函数为什么以及如何const修改对象的mutable数据成员?

成员函数使用this指针来修改对象的数据成员。this成员函数的指针是const指向常量的指针,而不是普通的数据成员。那么为什么总是可以修改mutable对象标记的数据成员,编译器是如何实现的呢?

c++ mutable c++11

0
推荐指数
1
解决办法
110
查看次数