2

以下代码无法编译,因为编译器foo::bar在遇到它时不知道是什么。

class foo : foo::bar {
    class bar {
    }
}

有什么方法可以编译这段代码(或它的一些变体)吗?

4

6 回答 6

7

如果继承自是bar一个实现细节,并且目标是避免污染全局命名空间(或库的命名空间),一种常见的方法是将这些实现细节放在名为detail. 例如,这是在Boost等库中使用的约定。

namespace super_cool_library {

    namespace detail {
        class bar { };
    }

    class foo : detail::bar {
    };

}

诚然,detail命名空间只是一个约定,但大多数人都明白,在所述命名空间内有龙。

编辑:

正如Emilio Garavaglia所建议的那样,如果需要对C++11 内部类具有相同的访问权限,则foo需要结交.detail::bardetail::barfoo

于 2013-11-12T07:42:33.177 回答
4

我不知道为什么,但我觉得这个问题很有趣。特别是看到有多少答案尽量不要给出语言不允许这样做的技术原因,而是试图让作者相信这种定义的“丑陋”(这最终是一个主观问题)。

尽管问题的形式看起来非常规,但所问的问题是完全线性的:因为递归是某些编程范式(C++ 声称支持,如函数范式)背后的原语之一,如果允许函数递归(或者直接或间接地)为什么同样不能适用于数据定义?

毕竟,如果所问的问题是可能的,那么元编程领域就会出现一系列有趣的特性:当泛型特征类用作泛型类的类型生成器时,在泛型状态之上定义泛型算法,具有像这样的构造函数可以允许(除其他外)将类型生成器放入泛型类本身,简化整体参数化,从而以完全不同的方式处理泛型算法及其“渐进式部分专业化”。

这不可能的原因是 C++ 编译器必须支持独立的翻译单元(编译后链接),并且必须支持非正交语法(这被称为“不可判定的语法问题”)。

由于这两个事实,C++ 不能有一个纯递归全局解析器。您不能使用“未知符号”让该符号与具体事物的关联在以后发生,因为解释该符号出现的表达式的方式取决于该符号本身的性质:a<b>c是变量的声明,还是涉及的表达式变量?你不知道你是否不知道 a 和 b 是变量还是类型。

并且由于“符号的性质”是“编译器内部状态”,因此在知道它确实是一个类(而不是变量或其他东西)之前,您不能使用foo::bar它,因为它是一个类(就像作为派生类的基础))。但这只会在以后发生(当满足类栏声明时)。

这与导致前向声明以及声明与定义分离的原因相同:a(b)如果至少a不知道是“可调用对象”,则无法进行转换。如果a是函数,则至少必须知道它的原型何时a(b)满足。

但是在您的情况下,无法预期foo::bar声明是 bar 声明以保留在 foo 定义中。

为了找到解决方案,语言应该支持类似的东西

1: class foo; //we know foo is a class
2: class foo::bar; // we know bar is a class inside foo scope

3: class foo::bar
   {
     ...
   }; //we know here how wide foo::bar is

4: class foo: public foo::bar // we must know about foo::bar width here...
   {
     ...
   }; //... to sum up the foo size.

这里的问题是这2:不是合法的 C++:编译器还没有bar单独看到符号,以及class它前面的单词。

但这需要

class foo
{
  class bar;
};

已经存在。但是如果你让它存在,你class foo: public bar {...};以后就不能再声明了。

In other words, you meet an non-orthogonality in the grammar. The point is that it will not be solved, since around this inconsistency there have been deployed a number of programming paradigms that does not require that construct to work, and have already make enough brainwashing to let sooo many people (just look at the comments in you question and under the most of the answers) the let them to just refuse the idea even before trying to understand if it can be useful to something. They just say "I don't like that something, since I just have something else to like, and that can disturb me. And try to find false metaphors to support motivations that -ultimately- reside in the old C compilation model C++ still has to deal with.

于 2013-11-12T09:14:14.527 回答
3

不可能让外部类从嵌套类继承。如果您考虑一下,这也没有多大意义。一个类派生自它的内部子类?这就像一条蛇吃自己的尾巴。

您更有可能希望两者共享通用方法。foo在这种情况下,您可以创建另一个为和提供通用接口/基础的类foo::bar

class common_base{ /*  ... "shared" content ... */ };

class foo : public common_base{
    class bar : public common_base {
        /* depending on what you want to do this can be empty */
    }
}
于 2013-11-12T07:21:50.547 回答
1

但是,您可以这样做:

struct A
{
    struct B
    {
    };
};

struct C : public A::B
{
};
于 2013-11-12T07:30:07.810 回答
0

我不认为 C++ 支持你想要的,但如果目标是避免用“bar”污染全局命名空间,那么将 bar 放入单独的命名空间怎么样?例如

namespace shums_private_namespace {
   class bar {
   };
};

class foo : shums_private_namespace::bar {
public:
   foo() {/* empty */}
};
于 2013-11-12T07:42:28.080 回答
0

我不知道您为什么要这样做,但是如果您正在寻找技巧,那么类似 CRTP 的事情总是很有趣:

template <typename T>
struct Foo : public T
{
    struct Bar
    {
    };
};

struct empty {};

int main()
{
    typedef Foo<empty>::Bar Bar;
    Foo<Bar> f;
}
于 2013-11-12T08:02:07.823 回答