3

我正在开发一个使用 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 {};

当调用解析到有效函数ala检查成员是否存在时,has_member_foo专门从哪里扩展,可能在基类中,C++11 版本。当派生类继承.std::true_typedeclval<T&>().foo(declval<T2&>())foo

4

1 回答 1

0

当您编写尝试调用的代码时,编译器会说什么bar

Derived d;
d.bar<int>(42);

如果它在那里显示错误,那么我认为事情正在按预期工作。在您实际编写使用模板方法的代码之前,没有要编译的内容,因此如果您使用的是不太智能的编译器,您可能看不到任何错误。

你甚至可以像这样定义 bar:

template <class T>
void bar( T t )
{
  foo( t );
  snarf();
  snorf();
  divideByZero();
  asdf--+|&*
}

只要您从不尝试使用 bar,它仍然可以编译(使用某些编译器)。

于 2013-06-21T20:01:52.963 回答