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

时间:2014-09-04 10:53:54

标签: 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的默认构造函数是私有的。

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

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

this page开始,我想如果表达式未被评估,我们可以使用私有默认构造函数。所以,我测试了以下内容来检查它。

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

正如所料,它没有被编译。

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

1 个答案:

答案 0 :(得分:11)

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

  

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

因此,即使在未评估的情况下,您仍然受到创建和销毁临时所需的任何函数(包括构造函数)的可访问性的限制。该说明的最后一句澄清了像declval这样的函数可以用来避免这个障碍。

相关问题