我有一些类来定义序列,这些序列的值在编译时通过value成员以及在运行时作为类型的实际实例都必须可用。所以我的算术序列的基本类型看起来像这样,

template<int A, int D>
struct ArithmeticSequence : public Sequence {
    ArithmeticSequence(VALUE v)
        : Sequence(v) {}

    template<unsigned int N>
    struct VALUE_N : public VALUE {
        static const int value = A+(D*N);
        operator int() { return value; }
    };
};
class Sequence当前仅定义一个内部类VALUE(当前为空)和一个接受VALUE的构造函数,但是我将operator int()VALUE_N移到VALUE中,并且Sequence将定义迭代器,依此类推。

现在,类应该从ArithmeticSequence扩展,并为序列的每个成员定义常量。我有两种方法可以解决此问题,如果我不介意序列的实例能够从相关序列的成员(即具有相同初始值和共同差异的序列)中构建,我可以使用typedef:
struct mySequence : public ArithmeticSequence<0,1> {
    mySequence(VALUE val = VALUE_N<0>::value)
        : ArithmeticSequence(val) {}

    typedef VALUE_N<0> zeroth;
    typedef VALUE_N<1> first;
    // ...
};

如果可以,我可以从VALUE_N扩展:
struct mySequence : public ArithmeticSequence<0,1> {
    mySequence(VALUE val = VALUE_N<0>::value)
        : ArithmeticSequence(val) {}

    struct zeroth : public VALUE_N<0> {};
    struct first  : public VALUE_N<1> {};
    // ...
};

在这两种情况下,我都可以使用mySequence::zeroth::value来获取编译时的值,并可以使用mySequence::zeroth()来获取运行时对象。但是,使用第二种方法会使编译器对我要声明函数还是初始化实例感到困惑,因此我需要使用mySequence s1 ((mySequence::zeroth()));而不是mySequence s1 (mySequence::zeroth())

现在,我发现以下内容是有效的,
struct mySequence : public ArithmeticSequence<0,1> {
    mySequence(VALUE val = VALUE_N<0>::value)
        : ArithmeticSequence(val) {}

    struct zeroth : public VALUE_N<0> {};
    static const zeroth zeroth;
    struct first  : public VALUE_N<1> {};
    static const first first;
    // ...
};

但是我的问题(最后)是,我随时都在访问哪个规则?我可以使用static const int i = mySequence::zeroth::valuemySequence s1 (mySequence::zeroth),所以似乎在那里发生了正确的事情,但是如果我说mySequence::zeroth z而不是将zeroth视为一个类,则会将其视为变量。在这种情况下,这不是问题,因为我不希望人们创建新的mySequence::zeroth或任何其他值,但是我想,如果我不明白何时使用它们,我可能会让自己陷入困境以后的日期。

抱歉,我们的帖子太长了,在此先感谢您的时间和耐心。我现在想知道我应该把所有的背景故事还是只是问一个问题,如果共识是我应该拥有的,我将其编辑下来。谢谢。

编辑。请注意,正如我上面所写的那样,使用struct方法而不是typedef不能提供任何保护,以防止使用另一个“相关”序列成员来构建序列对象,但是我认为这是必需的,但是对于最后一个示例上类。

最佳答案

枚举器,函数和对象的名称隐藏了在同一作用域中声明的枚举和类的名称。在您的情况下,数据成员名称将隐藏该结构的名称。您可以通过特殊查找访问隐藏的类型名称:

  • 通过忽略对象,函数和枚举器名称来查找::之前的名称。
  • 用于指定基类的名称将忽略所有非类型名称。
  • 在详细的类型说明符中指定的名称将忽略对象,函数和枚举器名称。

  • 因此,以下详细的类型说明符有效并引用了该类
    struct mySequence::zeroth var;
    

    另外,请注意,当成员声明在类范围内更改该声明中使用的名称的含义时,它的格式是错误的。在您的情况下,让我们采用static const first first;。名字将引用类型,但在mySequence的完整范围内,该名字将引用数据成员。标准说



    不需要编译器来诊断它,这是一个短语,表示它实际上是未定义的行为(好的编译器会通过“成员更改名称的含义”来警告您)。尽管我怀疑上面的规则是否打算在这种情况下适用(按其措辞,虽然它确实适用),但是您可以使用详细的类型说明符来清除代码
    struct first  : public VALUE_N<1> { };
    static const struct first first;
    

    请注意,您需要在静态成员的类外定义中使用详细的类型说明符。一些编译器允许您也使用注入(inject)的类名来引用类型(过去,GCC这样做过)
    const struct mySequence::first mySequence::first;
    

    以下使用注入(inject)的类名。 first出现在::之前,并忽略数据成员。但是编译器必须在mySequence::first::first的构造函数中查找名称first而不是其类类型
    const mySequence::first::first mySequence::first;
    

    关于c++ - 访问与内部类型同名的静态成员,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3273354/

    10-11 19:07