我发现很奇怪,尽管默认构造函数是private(4.8.1 g ++),但下面的程序仍然编译得很好:
class A{
private:
A() = default;
A(const A&) = default;
};
int main(){
A a;
}
Run Code Online (Sandbox Code Playgroud)
实际上从标准的8.4.2 [2](N3242)
显式默认函数只有在被隐式声明为constexpr时才可以声明为constexpr.如果在第一次声明中明确违约,
- 它应该是公开的,
..........
默认说明符忽略访问规范的目的究竟是什么?我觉得这可能会导致类设计者不希望用户创建默认值但需要实现中的默认构造函数的接口问题.我想也许是因为默认构造函数是正常的public,所以default复制它的目的 - 但这并不能解释为什么=default复制构造函数不会忽略private规范.
class A{
private:
A() = default;
A(const A&) = default;
};
int main(){
A a;
A b(a); //error: constexpr A::A(const A&) is private
}
Run Code Online (Sandbox Code Playgroud)
实际上我无法从标准中看到它提到明确默认的copy/move构造函数/赋值没有public.
class A {
int f(int x, int j) { return 2;}
decltype(f)* p;
};
Run Code Online (Sandbox Code Playgroud)
给我错误:
error: decltype cannot resolve address of overloaded function
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么这个错误甚至可以说是重载函数.同样地,我想也许我需要使用范围运算符来访问该函数:
class A {
int f(int x, int j) { return 2;}
decltype(A::f)* p;
};
Run Code Online (Sandbox Code Playgroud)
这仍然给我一个错误,但更清楚的描述:
error: invalid use of non-static member function 'int A::f(int, int)'
Run Code Online (Sandbox Code Playgroud)
为什么我不允许使用decltype来查找成员函数的类型?或者设置成员函数以static在任何一种情况下删除错误.
编辑:我重新格式化了帖子以便更清楚.
为什么这样做:
struct A {};
struct B {
B(A){}
};
void operator+(const B&, const B&) {}
int main()
{
A a1, a2;
a1 + a2;
}
Run Code Online (Sandbox Code Playgroud)
这不是吗?
struct B {
B(const char*){}
};
void operator+(const B&, const B&) {} //error: invalid operands of types 'const char [6]' and 'const char [6]' to binary 'operator+'|
int main()
{
"Hello" + "world";
}
Run Code Online (Sandbox Code Playgroud)
本质上,在第一个示例中a1,a2它们都B通过隐式转换转换为对象并使用operator+(const B&, const B&)添加.
从这个例子开始,我希望"Hello"并再次通过隐式构造函数"world"转换为B对象,并使用 …
#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <vector>
class Base{
public:
virtual ~Base() {}
};
class Derived: public Base { };
int main(){
int arr[10];
Derived d;
Base *p = &d;
std::map<std::type_index, std::string> proper_name = {
{typeid(int), "int"}, {typeid(double), "double"}, {typeid(float), "float"}, {typeid(char), "char"},
{typeid(Base), "Base"}, {typeid(Derived), "Derived"}, {typeid(std::string), "String"},
{typeid(int[10]), "Ten int Array"}, {typeid(p), "Base Pointer"}};
}
Run Code Online (Sandbox Code Playgroud)
我试图弄清楚这个列表初始化中发生的隐式转换.来自13.3.1.7N3337:
当非聚合类类型T的对象被列表初始化(8.5.4)时,重载决策分两个阶段选择构造函数:
最初,候选函数是类T的初始化列表构造函数(8.5.4),参数列表由初始化列表作为单个参数组成.
如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类T的所有构造函数,参数列表由初始化列表的元素组成.
8.5.4:
构造函数是初始化列表构造函数,如果它的第一个参数是类型
std::initializer_list<E>或引用,可能std::initializer_list<E>是某些类型的cv-qualifiedE,并且没有其他参数或者所有其他参数都有默认参数
所以下面的构造函数列表用于 …
我正在阅读C++ Primer,我对一些关于Bitwise运算符如何处理有符号类型的注释感到有些困惑.我会引用:
引用#1
(当谈到按位运算符时)"如果操作数是有符号的并且其值是负的,那么在许多按位运算中处理"符号位"的方式取决于机器.此外,执行左移位会改变符号位的值未定义"
引用#2
(当谈到右移操作符时)"如果该操作数是无符号的,则操作符在左侧插入0值位;如果是有符号类型,则结果是实现定义 - 符号位的副本或0值位插在左边."
按位运算符将小整数(例如char)提升为已签名的整数.当按位运算符经常在已签名的运算符类型上给出未定义或实现定义的行为时,此促销对于签名整数是否存在问题?为什么标准不会将char提升为unsigned int?
编辑:这是我提出的问题,但我已将其放回上下文,并在下面给出了一些答案.
之后的一个练习问道
" ~'q' << 6在具有32位ints和8位chars的机器上,使用其中'q'具有位模式的Latin-1字符集的价值是01110001多少?"
好吧,'q'是一个字符文字,将被提升为int,给予
~'q' == ~0000000 00000000 00000000 01110001 == 11111111 11111111 11111111 10001110
下一步骤是将左移位运算适用于上面的位,但作为报价#1提到
"做一个改变符号位值的左移是未定义的"
好吧,我不知道哪个位是符号位,但肯定答案是未定义的?
以下来自我的C++书籍的引文:
当我们使用直接初始化时,我们要求编译器使用普通函数匹配来选择与我们提供的参数最匹配的构造函数.当我们使用复制初始化时,我们要求编译器将右侧操作数复制到正在创建的对象中,必要时转换该操作数.
对我来说,这个粗体位会产生一些模糊性.它使得听起来像右手操作数被转换为类类型,然后使用复制构造函数,例如;
string s = "hello";
Run Code Online (Sandbox Code Playgroud)
会成为...
string s = string("hello");
Run Code Online (Sandbox Code Playgroud)
它使用复制构造函数.如果这是真的那么我的测试程序;
#include <iostream>
using namespace std;
class A{
public:
A(const A& b): data(b.data) { cout << "The first way" << endl;}
A(const char* c): data(c) { cout << "The second way" << endl;}
string data;
};
int main(){
A first("hello");
A second = "sup";
}
Run Code Online (Sandbox Code Playgroud)
应该产生"第二种方式,第二种方式,第一种方式".然而它反而打印出"第二种方式,第二种方式".从这里我可以得出结论它是使用const char*构造函数而不是复制构造函数.我会好的,除非后来说......
在复制初始化期间,允许编译器(但没有义务)跳过复制/移动构造函数并直接创建对象.也就是说,允许编译器重写
Run Code Online (Sandbox Code Playgroud)string null_book = "9-999-99999-9";成
Run Code Online (Sandbox Code Playgroud)string null_book("9-999-99999-9");但是,即使编译器省略了对复制/移动构造函数的调用,复制/移动构造函数也必须存在,并且必须在程序中的该点可访问(例如,非私有).
我不确定为什么复制构造函数甚至需要在这些示例中提及,否则
string null_book = "9-999-99999-9"
Run Code Online (Sandbox Code Playgroud)
总是隐含地意味着仍然使用const char*构造函数?实际上,我不需要定义复制构造函数以使上述工作正常.但是,如果我将"const A&"构造函数设置为私有(其他公共),那么我的程序将无法运行.为什么必须为不涉及它的隐式转换定义复制构造函数?什么构造函数"string null_book …
c++ copy-constructor implicit-conversion copy-initialization copy-elision
我搜索过谷歌,但没有找到我的查询的直接答案.
我一直在阅读C++ Primer,我对这门语言还很陌生,但尽管这本书有多好,但它讨论了标准库的使用,但并没有真正描述它的位置或来自何处(它没有'无论如何).那么,标准库在哪里?哪些头文件可以让我访问它?当我下载CodeBlocks时,STL是否附带了它?或者它是自动附带我的操作系统?
有点相关,但Cobeblocks带来的MinGW究竟是什么?在这里说
MinGW是一个C/C++编译器套件,它允许您创建Windows可执行文件而不依赖于此类DLL
所以在最基本的层面上它只是让我制作C++程序所需的"东西"的集合?
对这个非常基本的问题道歉.
鉴于C++ Primer对本地静态对象的描述:
拥有一个本地变量可能很有用,该变量的生命周期会持续调用该函数.我们通过将局部变量定义为静态来获取此类对象.在第一次执行通过对象的定义之前,将初始化每个本地静态对象.当函数结束时,不会破坏局部静态; 它们在程序终止时被销毁.
我惊讶地发现以下代码编译良好,具有合理的输出:
#include <iostream>
using namespace std;
void test(int x){
static int y = x;
cout << y;
}
int main(){
test(2);
test(5);
test(6);
}
Run Code Online (Sandbox Code Playgroud)
通过这样的描述,似乎使用函数参数进行初始化是不可能的或没有多大意义,它如何y在执行通过函数之前初始化,它将如何知道它是什么x?这是C++ Primer的过度简化,还是我的程序可能出现编译器无法检测到的错误?
对于那些想知道为什么我可能尝试使用参数初始化静态变量的人,我试图创建一个函数,用于default_random_engine在每次调用时返回所提供范围内的随机整数(因此需要static因此对象不是销毁)作为C++ Primer的另一个练习的一部分:
unsigned randomUns(unsigned minV, unsigned maxV, default_random_engine::result_type seed = 0){
static default_random_engine e(seed);
static uniform_int_distribution<unsigned> u(minV, maxV);
return u(e);
}
Run Code Online (Sandbox Code Playgroud) c++ ×8
c++11 ×3
addition ×1
codeblocks ×1
constructor ×1
copy-elision ×1
decltype ×1
function ×1
literals ×1
local ×1
member ×1
signed ×1
static ×1
string ×1