简体   繁体   中英

What is top-level in C++?

In example 14 under [dcl.init.list] , the standard uses the term "top-level" when describing the semantics of code using list-initialization, in the context of narrowing conversions. I don't know what this means.

This code executes without errors:

int f(int a) { return 1;}

int main() {
    int a[] = {f(2), f(2.0)};  
    int b[] = {f(2.0), f(2)}; // No error because: double-to-int conversion is not at the top-level
}

I also tried the following. I figured it is nothing to do with the order of initialization:

int f(int a) { return 1;}

int main() {
    int a[] = {f(2), f(2.0)};  
    int b[] = {f(2.0), f(2)}; // double-to-int conversion is not at the top-level
    //int c[] = {f(2147483645.0f), f(2)}; // This is erroring out due to narrowing.
    int d[] = {f(2), f(2.0)};  // Now I'm sure top-level doesn't mean the order of initialization. 
}

I want to know what is a top-level? The documentations here and here do not describe it.

The reason I'm curious about this term is because I'm trying to understand when would list-initializers work when narrowing conversion is implicitly invoked.

I'm also not sure about the terminology. For example, is there something like a top-level class, or a top-level type, or a top-level list-initializer?

This is not a strictly defined term. But in [dcl.init.list]/note-7 that you linked, "at the top level" seems to mean "written directly in a braced list, rather than in a nested expression".

So, in int x[] = {1.0, f(2.0)}; , 1.0 is at the top level, because it's written directly in the braced list, but 2.0 is not because it's nested in a function-call expression.

This is not a rigorously defined C++ standard term. Instead, it was just meant in the sloppy English language sense. You can imagine someone using other phrases, like "earlier in the function" or "the corresponding header file", which are not technically C++ terms but would be widely understood.

In this case, they're referring to a higer level of nesting. For example, consider this snippet:

void foo() {
    int j[2][2] = {{3, 4}, {5, 6}};
}

Clearly 4 is more deeply nested then {3, 4} , which in turn is more nested than {{3, 4}, {5, 6}} . In fact, {{3, 4}, {5, 6}} is not nested at all. The author of the text you read would call this at the "top level".

Another author might argue that foo is on the "top level", so it depends on context to an extent. In the quotation you posted, the meaning is clear though.

It is just an English phrase meant to be taken in context.

The rules of [dcl.init.list] tell us how an item in a list-initialiser cannot involve a narrowing conversion. Note 7 goes on to remind us of this, using the term "top-level" to describe those things that it's talking about (the immediate "members" of the list).

Example 14, which you are referring to, further includes an example of where a statement with a list-initialisation happens to contain a narrowing conversion, but the comment reminds us that this is fine because the conversion occurs at a "lower level" of nesting, again using the term "top-level" to describe the entities listed immediately in the initialiser list. No narrowing conversion was required to be applied to the actual list item.

There is no formal definition of the term "top-level"; it's supposed to be interpreted in its English sense while considering the possible nesting at play.

I was confused about this a while back, but I think I understand this concept fairly well now.

Before I go to explain the concept, it must be noted that it is not the object that is top-level or low-level, but it is the "const" that is top-level or low-level depending it's position in the expression or context.

Top-level const means (that) "const" is making the object itself const (no matter what that object is pointing to).

Low-level const means (that) "const" is indicating that the object being referred(/pointed) to is const.

Ex.

const int i = 10; // const is indicating that i itself is const so it (const) is top level.

const int const *p = &i; // leftmost const is indicating that "pointed to" is const, so that const is low-level, other const in the expr is top-level.

Also, Top-level consts can appear with any obj type (Build in types, class type, pointer types), whereas Low-level const appears in base type of the compound types such as pointers & refs.

In pointers, both low-level and top-level can appear, but in refs, consts are always low-level, because refs are implicitly have top-level consts (once initialised, refs can't be bound to other objs, so in a sense they implicitly have top-level const on to them).

Hope that helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM