c++ - 使用元编程的私有(private)成员存在性测试,GCC vs clang,哪个是对的?

标签 c++ gcc clang

这更像是一个 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 版本 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 的声明。

Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions.

最佳答案

我认为 GCC 是正确的。

首先要注意的是,没有非 friend代码应该能够积极报告给定私有(private)成员的存在。所以如果那是你想做的,你必须修改你的设计。一个类可以对其私有(private)成员做任何事情,其他代码( friend 除外)应该无法知道它。这是设计使然。

但是,有 SFINAE原则:替换失败不是错误。自 MyClass::Data是私有(private)的,has_Data中的代码在我看来,应该像没有C::Data一样行事。完全是成员(member)。因此第一个函数会导致替换失败,它会被默默地忽略,而第二个函数是使用的那个。添加更多代码,我的 GCC 4.7.2 可以毫无问题地编译它并使用 has_Data<MyClass>::value评估为 false .在我看来正确的 SFINAE。

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

Note: Access checking is done as part of the substitution process.

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

编辑作为@hvda 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 语义,我不会费心就此提交报告。

关于c++ - 使用元编程的私有(private)成员存在性测试,GCC vs clang,哪个是对的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16206626/

相关文章:

c++ - 如何使用 msxml 解析器创建子元素?

gcc -/usr/bin/ld : Cannot Find -l Error (Using GCC in Linux GCC Linker Error)

gcc - 在 OS X 10.9 Mavericks 上编译 Mesos 时如何修复 "implicit instantiation"错误?

c++ - 为什么这个变量被标记为 "unused"?

c++ - 用 libclang : getting CXX_BASE_SPECIFIER cursors when base types unknown 解析

c++ - QT4没有这个信号

c++ - std::shuffle 的顺序可以依赖于 RNG 之外的任何东西吗?

c++ - 在其他私有(private)类成员中使用私有(private)类成员

c - 是否可以将命令行参数传递给 GNU LD 以创建一个部分、定义大小并将其放置在特定内存中?

CS50 IDE clang : error: linker command failed with exit code 1