为什么来自常量POD对象的字段本身不是常量?

3

我想为特定的GUID专门制作一个模板,它是一个16个字节的结构体。 GUID对象具有内部链接,因此无法使用对象本身的地址,但我认为可以使用对象的内容,因为该对象是常数。 但是这种方法不起作用,如以下示例代码所示:

struct S
{
    int const i;
};
S const s = { 42 };
char arr[s.i];

为什么s是常量而s.i不是?有什么解决方法吗?

2
仅仅因为 i 被标记为 const 并不意味着它的初始化也是常量。 - Xeo
如果你这样做 S const s = someMethodThatReturnsSomeS(); 会怎么样? - Luchian Grigore
对于专门类型的每个对象,s.i 的值是否相同?因为这可以很容易地处理。此外,一些来自专门化的代码将非常有用。 - Ryan Haining
@xhainingx 我提出了一个后续问题,描述了我想要在这里实现的内容。https://dev59.com/2G_Xa4cB1Zd3GeqP3aa1 - Bruno Martinez
2个回答

7
结构体 s 的初始化可以在运行时进行。然而,数组的大小必须在编译时知道。编译器不能(肯定)知道 s.i 的值在编译时已知,因此它只看到你在用一个变量来做你不应该做的事情。问题不在于常量性,而在于需要数组大小的时间。
您可能误解了 const 的含义。它只意味着变量初始化后永远不会改变。例如,这是合法的:
void func(int x){
    const int i = x*5; //can't be known at compile-time, but still const
    //int array[i]; //<-- this would be illegal even though i is const 
}

int main(){
    int i;
    std::cin >> i;
    func(i);
    return 0;
}

为了避免这个限制,在C++11中,你可以将其标记为constexpr,表示该值可以在编译时确定。这似乎是你想要的。
struct S
{
    int const i;
};
int main(){
    constexpr S const s = { 42 };
    char arr[s.i];
    return 0;
}

使用以下命令进行编译:

$ c++ -std=c++11 -pedantic file.cpp


在C99中,您所做的是合法的,数组的大小不需要在编译时知道。

struct S
{
    int const i;
};
int main(){
    struct S const s = { 42 };
    char arr[s.i];
    return 0;
}

compile with:

$ cc -std=c99 -pedantic file.c


2

至少在大多数情况下,const 的意思更接近于“只读”而不是“常量”。在 C89/90 中,它基本上只表示“只读”。C++ 添加了一些可以使其成为常量的情况,但它仍然远远不能全部(不幸的是,准确记录它的含义何时是非常棘手的)。

幸运的是,“解决方法”是以你几乎肯定应该采用的方式编写代码:

std::vector<char> arr(s.i);

底线是:在C++中,大多数使用内置数组的方法都应该被视为可疑的。你可以从非常量表达式初始化向量只是其中许多优点之一。

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