c++ - 为什么我可以在 decltype() 中使用私有(private)默认构造函数?

标签 c++ c++11 language-lawyer private-members 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 的默认构造函数是私有(private)的。

However, it works well.我难以置信地在我的 g++ 4.8.3 上用 -Wall -Wextra -Werror -pedantic 测试了它,但它运行良好,没有任何错误或警告。

(此外,它似乎也适用于 GCC 4.9.1。)

来自 this page ,我想如果表达式未被评估,我们可以使用私有(private)默认构造函数。因此,我测试了以下内容以进行检查。

#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
}

(live example)

正如预期的那样,它没有被编译。

但是.... 为什么?? 这怎么可能?我们可以在未评估的表达式中使用 private 成员吗?还是默认构造函数有特殊规则?你能解释一下为什么吗?

最佳答案

它不应该编译。 C++11 [class.temporary] 关于创建临时对象有这样的说法:

12.2/1 Even when the creation of the temporary object is unevaluated or otherwise avoided, all the semantic restrictions shall be respected as if the temporary object had been created and later destroyed. [ Note: even if there is no call to the destructor or copy/move constructor, all the semantic restrictions, such as accessibility and whether the function is deleted, shall be satisfied. However, in the special case of a function call used as the operand of a decltype-specifier, no temporary is introduced, so the foregoing does not apply to the prvalue of any such function call. — end note ]

因此,即使未计算,您仍然受到创建和销毁临时对象所需的任何函数(包括构造函数)的可访问性的限制。注释的最后一句话阐明了像 declval 这样的函数可以用来避免这个障碍。

关于c++ - 为什么我可以在 decltype() 中使用私有(private)默认构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25663642/

相关文章:

c++ - C/C++ - 指针传递给 DLL 中的函数

c++ - 在 C++ 中放置新的和对齐

c++ - 将模板化实现分配给先前声明的函数

c++ - 如何将枚举导入 C++ 中的不同命名空间?

c++ - 使用 gtest 1.6 : how to check what is printed out? 进行单元测试

c++ - 自定义堆中的段错误

c++ - 我的基于可变参数模板的包装函数有什么问题?

c++ - std::cspan 发生了什么?

c++ - 一个默认的默认构造函数,为什么不是用户提供的默认构造函数呢?

c++ - Qt4 与 UI 线程的接口(interface)