这更像是一个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),我发现一个声明似乎与gng一致而不是gcc的声明。
访问控制统一应用于所有名称,无论名称是从声明还是表达式引用。
答案 0 :(得分:3)
我认为海湾合作委员会是对的。
首先要注意的是,没有非friend
代码应该能够正确地报告给定私有成员的存在。因此,如果您尝试这样做,则必须修改您的设计。一个类可以对其私有成员执行任何操作,而其他代码(除了朋友)应该无法知道它。这是设计的。
但是,有SFINAE原则:替换失败不是错误。由于MyClass::Data
是私有的,has_Data
中的代码应该 - 在我看来 - 就好像根本没有C::Data
成员一样。因此,第一个函数会导致替换失败,它会被忽略,第二个函数就是使用的函数。添加更多代码,我的GCC 4.7.2编译时没有问题,has_Data<MyClass>::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详细说明了这一变化。
由于-std=c++03
是GNU扩展,GCC不会使用-std=c++11
或typeof
编译此代码。 -std=gnu++03
仍然编译代码的事实可能被认为是不合适的,但由于前进的方式是使用C ++ 11语义,我不打算提交关于此的报告。