在从模板派生之前访问模板的基类。

5

我想公开从一个模板派生一个类,使它继承自一个基类并获得对受保护成员的访问。但在模板被展开之前,它没有这些权限,因此它不能将一个Base成员用作模板参数:

using Fun = void (*)();

class Base {
protected:
    // friend class Derived; // ...need this to eliminate complaint
    static void something();
};

template<Fun F>
class Variant : public Base {};

class Derived : public Variant<&Base::something> { // `something()` is protected
public:
    void somethingElse() {
        something(); // doesn't complain about this `something()`
    }
};

int main() {}

对我来说,这个问题的奇怪之处在于添加友元居然起作用。我想知道是否可以通过在 Variant 前从 Base 进行公共虚拟继承来“偷偷摸摸地将 Derived 引入其中”:

class Derived : public virtual Base, public Variant<&Base::something>

那没有帮助。

问题:有没有其他技巧可以避免在Base中显式提及所有派生类,但仍然可以访问它的受保护成员以供模板参数使用?

(注意:在旧版gcc 4.6.3上尝试这一点,看起来即使是友元也无济于事。因此,支持这一点似乎是相对较新的。)


3
相关:CWG 372CWG 580。目前似乎即使是最新版本的clang++和g++也没有实现对后一个缺陷提出的解决方案。 - dyp
@dyp 我想这可能是“答案”,或者说这是我们能得到的最接近的答案。你想把它变成一个吗? - HostileFork says dont trust SE
1个回答

1
将有问题的访问方式放入元函数中。从基类派生出元函数类。
template<typename B>
struct something_variant : public B {
    typedef Variant< & B::something > type;
};

class Derived : public something_variant<Base>::type {
    …

http://coliru.stacked-crooked.com/a/6bca00455bd3daca

关于CWG 372,决议中的关键文本如下:
“在看到整个基类列表之前,必须推迟对基类限定符的访问检查。”
这已经在C++11中得到了接受,所以有趣的是你的示例被拒绝了。并且,将相关示例代码从C++11标准插入到最近的Clang和GCC中,可以证明它们没有实现推迟。这至少有点令人惊讶,因为实现需要一些数据结构来表示一组推迟的访问检查……对于一个角落案例而言,这需要相当高的工作量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接