【问题标题】:Private member existence test using meta programming, GCC vs clang, which is right?使用元编程的私有成员存在测试,GCC vs clang,哪个是正确的?
【发布时间】:2013-04-25 04:51:56
【问题描述】:

这更像是一个 c++ 标准问题。 考虑以下代码:

template <typename T>
class has_Data
{
   typedef char one;
   typedef long two;

   template <typename C> static one test( typeof(&C::Data) ) ;
   template <typename C> static two test(...);

public:
   enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

class MyClass {
private:
   struct Data {
   };
};


void function(bool val = has_Data<MyClass>::value) {}

以上代码适用于gcc (GCC) 4.4.3

但是clang version 3.3 (2545b1d99942080bac4a74cda92c620123d0d6e9) (2ff97832e593926ea8dbdd5fc5bcf367475638a9)

它给出了这个错误:

test_private_data.cpp:7:54: error: 'Data' is a private member of 'MyClass'
   template <typename C> static one test( typeof(&C::Data) ) ;
                                                     ^
/devshared/home/rhanda/test_private_data.cpp:7:37: note: while substituting explicitly-specified template arguments into function template 'test'
   template <typename C> static one test( typeof(&C::Data) ) ;
                                    ^
/devshared/home/rhanda/test_private_data.cpp:21:26: note: in instantiation of template class 'has_Data<MyClass>' requested here
void function(bool val = has_Data<MyClass>::value) {}
                         ^
1 error generated.

哪个是对的?

从标准文档 (n3485) 中,我发现了一个似乎比 gcc 更同意 clang 的声明。

访问控制统一应用于所有名称,无论名称是从声明还是表达式中引用。

【问题讨论】:

  • 您的意思是template &lt;typename C&gt; static one test( typename C::Data * );?我只是好奇decltype( &amp;C::Data ) 为你做了什么……
  • 它是一样的..只是检测函数是否可以解析为第一个函数..如果我改变使用你的代码..它做同样的事情,我想。
  • @RamneekHanda decltype( &amp;C::Data ) 不是 type of pointer to a data-member C::Data 吗?因为,如果您确实按照所示运行测试,function() 参数val 是0。你不是说要1 换成MyClass 吗?
  • 请注意,typeof 不是 C++ 标准的一部分,它是 GCC 扩展。

标签: c++ gcc clang


【解决方案1】:

我认为 GCC 是正确的。

首先要注意的是,没有非friend 代码应该能够肯定地报告给定私有成员的存在。因此,如果这是您尝试做的事情,则必须修改您的设计。一个类可以用它的私有成员做任何事情,其他代码(除了朋友)应该没有办法知道它。这是设计使然。

但是,有SFINAE的原则:替换失败不是错误。由于MyClass::Data 是私有的,所以has_Data 中的代码应该——在我看来——就像根本没有C::Data 成员一样。因此,第一个函数会导致替换失败,它会被默默地忽略,而第二个函数就是使用的那个。添加更多代码,我的 GCC 4.7.2 编译它没有问题,has_Data&lt;MyClass&gt;::value 评估为false。我认为正确的 SFINAE。

试图用the document you referred to 的引用来支持这一观点,我在第 14.8.2 节第 8 段中找到了以下内容:

注意:访问检查是替换过程的一部分。

这是标准中的非规范性注释,但对我来说似乎是一个非常易读和明确的指示,表明 SFINAE 实际上应该适用于这种情况,就像 GCC 处理它的方式一样。

编辑: 正如@hvd 在a comment 中指出的那样,以上仅适用于C++11。在旧版本的标准中,情况过去有所不同。 Issue 1170: Access checking during template argument deduction 有关于该更改的详细信息。

GCC 不会使用-std=c++03 或-std=c++11 编译此代码,因为typeof 是一个GNU 扩展。 -std=gnu++03 仍然编译代码的事实可能被认为是不合适的,但由于前进的方向是使用 C++11 语义,我不会费心提交关于此的报告。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-02
  • 2016-09-15
  • 1970-01-01
  • 2019-06-04
  • 2015-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多