为什么我可以在decltype()中使用私有默认构造函数
Why can I use private default constructor in decltype()?
查看代码:
#include <iostream>
#include <utility>
class test
{
private:
test() { }
public:
test foo() { return *this; }
static const char *name() { return "test"; }
};
int main()
{
std::cout << decltype(test().foo())::name() << std::endl; // 1
std::cout << decltype(std::declval<test>().foo())::name() << std::endl; // 2
}
我希望// 1
行无法编译,因为test
的默认构造函数是私有的。
然而,它运行良好。我难以置信地在我的g++4.8.3上用-Wall -Wextra -Werror -pedantic
测试了它,但它运行良好,没有任何错误或警告。
(此外,它似乎在GCC 4.9.1中也能很好地工作。)
从这个页面,我想如果表达式未赋值,我们可以使用私有默认构造函数。所以,我测试了以下内容来检查它。
#include <iostream>
#include <utility>
class test
{
private:
test(int) { }
public:
test foo() { return *this; }
static const char *name() { return "test"; }
};
int main()
{
std::cout << decltype(test().foo())::name() << std::endl; // 1
std::cout << decltype(std::declval<test>().foo())::name() << std::endl; // 2
}
(实例)
不出所料,它没有被编译。
但是为什么这怎么可能?我们可以在未赋值的表达式中使用私有成员吗?或者对于默认构造函数有一个特殊的规则吗?你能解释一下为什么吗?
它不应该编译。C++11[class.temporary]对创建一个临时对象有这样的看法:
12.2/1即使临时对象的创建是未评估的或以其他方式避免,所有语义限制都应得到尊重,就好像临时对象已经创建并随后被销毁一样。[注意:即使没有对析构函数或复制/移动构造函数的调用,也应满足所有语义限制,如可访问性和函数是否被删除。但是,在函数调用用作decltype说明符的操作数的特殊情况下,不会引入临时性,因此上述内容不适用于任何ch函数调用。--尾注]
因此,即使未评估,您仍然受到创建和销毁临时所需的任何函数(包括构造函数)的可访问性的限制。注释的最后一句阐明了像declval
这样的函数可以用来避免这个障碍。
相关文章:
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 初始化具有非默认构造函数的std::数组项的更好方法
- 具有默认模板类型的默认构造函数的类型推导
- 如何使用非默认构造函数实例化模板化类
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 声明没有默认构造函数的字段
- 没有默认构造函数作为模板参数的自定义比较器
- C++17 没有默认构造函数的地图放置(私有默认构造函数)
- 使用移动调用对等构造函数unique_ptr默认构造函数
- C++复制构造函数和默认构造函数
- 将向量从 N1 缩小到 N2 项,而不触发默认构造函数并仅使用 move 语义
- 为什么即使我调用参数化构造函数也会调用默认构造函数?
- 具有非默认构造函数的单例类
- 在 C++ 中声明 const 对象需要用户定义的默认构造函数.如果我有一个可变成员变量,为什么不呢?
- 如何处理没有默认构造函数但在另一个构造函数中构造的对象?
- 在C++中使用默认构造函数初始化对象的不同方法
- 在没有默认构造函数的情况下创建的派生对象
- 强制使用默认构造函数对成员进行未初始化的声明
- 使用默认构造函数初始化对象的不同方法
- 创建类类型的动态分配数组,其中类不得具有默认构造函数