【问题标题】:Why can I use private default constructor in decltype()?为什么我可以在 decltype() 中使用私有默认构造函数?
【发布时间】:2014-10-29 02:16:22
【问题描述】:

看代码:

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

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

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

【问题讨论】:

  • 不能在 clang 中编译。
  • @T.C.哦真的吗?那么它可能只是GCC的错误..
  • 嗯,C++98 没有decltype。或declval。当然它不会编译。
  • @T.C.哦,我的大脑被搞砸了;;
  • 嗯,它甚至在 GCC 4.9.1 中编译...

标签: c++ c++11 language-lawyer private-members decltype


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢。 最后一句话 +1。 (哦,我知道我不能在一分钟内接受答案>o
  • 那一定是gcc的bug;我应该报告吗? >o
猜你喜欢
  • 1970-01-01
  • 2011-11-05
  • 2013-03-20
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 1970-01-01
  • 2018-11-25
相关资源
最近更新 更多