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

ikh*_*ikh 7 c++ decltype private-members language-lawyer c++11

看看代码:

#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
}
Run Code Online (Sandbox Code Playgroud)

我期望// 1行无法编译,因为默认构造函数test是private.

但是,它运作良好.-Wall -Wextra -Werror -pedantic怀疑地在g ++ 4.8.3上对它进行了测试,但它运行良好,没有任何错误或警告.

(此外,它似乎也适用于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
}
Run Code Online (Sandbox Code Playgroud)

(实例)

正如所料,它没有编译.

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

Mik*_*our 11

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

12.2/1即使临时对象的创建未被评估 或以其他方式避免,也应尊重所有语义限制,就好像临时对象已被创建并随后被销毁一样.[ 注意:即使没有调用析构函数或复制/移动构造函数,也应满足所有语义限制,例如可访问性和函数是否被删除.然而,作为一个的操作数的函数调用的特殊情况decltype说明符,没有临时的引入,因此上述不适用于任何此类函数调用的prvalue.- 结束说明 ]

因此,即使未经评估,您仍然受限于创建和销毁临时所需的任何函数(包括构造函数)的可访问性.该说明的最后一句澄清了类似的功能declval可用于避免这一障碍.