简体   繁体   English

在 class 上下文中使用时,前向声明与就地前向声明的工作方式不同

[英]Forward declarations don't work the same as in-place forward declarations when used in class context

I'm poking around in the myst of C++ instantiation / declaration order.我正在探索 C++ 实例化/声明顺序的奥秘。 Here's a fun bit I came across:这是我遇到的一个有趣的点:

This compiles:这编译:

#include <cstddef>
#include <variant>
#include <array>

template <size_t V>
struct container
{
    // THIS COMPILES
    struct array;
    using val = std::variant<std::monostate, int, array>;

    // THIS DOESNT
    // using val = std::variant<std::monostate, int, struct array>;

    struct proxy : val
    {
        using val::variant;
    };

    struct array { };
};

int main()
{
    container<10> ctr;
}

But when you opt for in-place declarations, it suddenly stops working ( Demo ):但是当您选择就地声明时,它突然停止工作( Demo ):

#include <cstddef>
#include <variant>
#include <array>

template <size_t V>
struct container
{
    // THIS COMPILES
    // struct array;
    // using val = std::variant<std::monostate, int, array>;

    // THIS DOESNT
    using val = std::variant<std::monostate, int, struct array>;

    struct proxy : val
    {
        using val::variant;
    };

    struct array { };
};

int main()
{

    container<10> ctr;
}

This is the error I get:这是我得到的错误:

/opt/compiler-explorer/gcc-trunk-20220729/include/c++/13.0.0/type_traits:1012:52: error: static assertion failed: template argument must be a complete class or an unbounded array
 1012 |       static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
      | 

Can someone explain me exactly why this happens?有人可以确切地解释为什么会发生这种情况吗? What is the difference?有什么区别?

EDIT : You are allowed in certain circumstances to declare a type in a template argument list:编辑:在某些情况下,您可以在模板参数列表中声明一个类型:

#include <cstddef>
#include <variant>
#include <array>
#include <cstdio>

void foo(std::initializer_list<struct array>);

struct array
{
    array(int a) : a_{a} {}
    void print() {
        printf("%d\n", a_);
    }
    int a_;
};

void foo(std::initializer_list<struct array> init) {
    for (auto a : init) {
        a.print();
    }
    printf(".. it works\n");
}

int main()
{
    foo({1,2,3});
}

I don't know when and where this applies though.我不知道这适用于何时何地。

A declaration of the form表格声明

class-key attribute-specifier-seq (opt) identifier ;类键属性说明符序列(选择)标识符;

(where class-key means struct , class , or union ), declares the identifier in the scope where the declaration appears ( [dcl.type.elab]/2 ). (其中class-key表示structclassunion ),在声明出现的 scope 中声明标识符[dcl.type.elab]/2 )。 That means in your first code snippet, array is forward declared as a member class of the container class template and you can later define it within the same scope.这意味着在您的第一个代码片段中, array被前向声明为container class 模板的成员 class,您可以稍后在同一个 scope 中定义它。

When an elaborated-type-specifier such as struct array appears as a component of some larger declaration or expression, [dcl.type.elab]/3 applies.当诸如struct array之类的详细类型说明符作为某个更大的声明或表达式的组件出现时, [dcl.type.elab]/3适用。 First, the compiler looks up the name array , ignoring anything that is not a type ( [basic.lookup.elab]/1 ).首先,编译器查找名称array ,忽略任何非类型( [basic.lookup.elab]/1 )。 If it doesn't find anything, then it forward-declares array in "the nearest enclosing namespace or block scope".如果它没有找到任何东西,那么它将在“最近的封闭命名空间或块范围”中前向声明array Consequently, the struct array that you later define as a nested class is a different class, and the one you referred to as struct array earlier has no definition.因此,您稍后定义为嵌套 class 的struct array是不同的 class,而您之前称为struct array的那个没有定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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