我正在开发一个项目,其中SFINAE用于检测成员函数是否存在。我遇到了以下示例的问题:
class Base
{
private:
template <class T>
void foo( T t ) {}
void snarf() {}
};
class Derived : public Base
{
public:
template <class T>
void bar( T t )
{
foo( t ); // shouldn't be possible
snarf(); // bug in gcc, correctly identified as error in clang
}
};
问题似乎是在尝试访问继承的函数时,派生类中没有遵守基类中的访问控制(例如私有)。 foo和snarf都不应该从派生类中访问。因此,当我尝试测试某些派生类是否具有某些功能时,它会错误地访问基类以找到匹配项。
在g ++ 4.8.1中,错误地允许调用foo和snarf,我很确定这是一个错误的实例:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41437
在clang ++ 3.3中,调用snarf被正确识别为错误,但允许调用foo,这似乎也应该是一个错误。这看起来像clang ++中的错误吗? (我发布了一个错误报告,以防它被证明是http://llvm.org/bugs/show_bug.cgi?id=16410)
鉴于这可能是两个编译器中的错误,我是否可以使用任何聪明的解决方法来检测派生不能真正访问foo?我实际使用它的方式如下:
template <class T, class T2, class Unused = void>
struct has_member_foo : std::false_type {};
has_member_foo
专门用于在调用std::true_type
时将declval<T&>().foo(declval<T2&>())
解析为有效函数ala Checking a member exists, possibly in a base class, C++11 version。当派生类继承私有版本foo
时,我需要这个失败。
答案 0 :(得分:0)
当您编写试图调用bar
的代码时,编译器会说什么?
Derived d;
d.bar<int>(42);
如果它在那里显示错误,那么我认为事情正在按预期工作。在您实际编写使用模板方法的代码之前,没有什么可编译的,因此如果您使用的是较不智能的编译器,则可能看不到任何错误。
你甚至可以像这样定义吧:
template <class T>
void bar( T t )
{
foo( t );
snarf();
snorf();
divideByZero();
asdf--+|&*
}
它仍将编译(使用一些编译器),只要你从不尝试使用bar。