Подтвердить что ты не робот

Почему это является прямой декларацией в С++?

У меня будет следующий фрагмент кода в файле utilA.cpp:

// utilB.h
namespace xm
{
     void zoo(struct tm timeval);  //<-----line 0
}


// utilA.cpp
#include <utilB.h>                 //<----line 1
#include <time.h>                  //<----line 2
namespace xm
{
     void foo()
     {
         struct tm time1 = {0};    //<----line 3
     }
}

GCC жалуется при компиляции utilA.cpp,

error: variable 'xm::tm time1' has initializer but incomplete type

Похоже, это потому, что utilA.h использует struct tm в строке 0, но не включает time.h, а компилятор обрабатывает struct tm в строке 0 в качестве прямого объявления, поэтому struct tm в строке 2 разрешается как xm::tm внутри заголовка в строке 0.

Значит, стандарт С++ определяет этот struct tm как тип параметра функции как форвардное объявление? Пожалуйста, помогите объяснить это, и цитаты из стандарта будут полезны.

4b9b3361

Ответ 1

В строке 0 вы объявили класс с именем tm внутри пространства имен xm. Да, С++ позволяет объявлять типы в параметрах функции/шаблона.

N4140 § 3.4.4 [basic.lookup.elab]/2

Если специфицированный тип-спецификатор вводится ключом класса и этот поиск не находит ранее объявленное имя типа, или если специфицированный тип-спецификатор появляется в объявлении с формой:

идентификатор атрибута-спецификатора класса-seq opt;

специфицированный спецификатор типа - это объявление, которое вводит class-name, как описано в разделе 3.3.2.

Поскольку вы объявили класс с именем tm внутри пространства имен xm, это первое имя, которое находит поиск имени для tm в строке 3. ::tm::std::tm) не рассматриваются. И поскольку нет определения класса ::xm::tm, компилятор жалуется на то, что он является неполным типом.

Если вы не пишете C-код на С++, вы должны написать что-то вроде 1

struct tm;

namespace xz{
    void zoo(tm timeval);
}

или

#include <ctime>

namespace xz{
    void zoo(tm timeval);
}

и у вас не было бы этой проблемы.

1 помните, что вы не можете перенаправлять объявления в пространстве имен std

Ответ 2

Итак, стандарт С++ определяет этот struct tm как тип параметра функции как форвардное объявление. Пожалуйста, помогите объяснить это, и квота из стандарта будет полезна.

Да, struct tm timeval вводит здесь новое имя класса xm::tm.


(пояснения и цитаты)

struct tm является специфицированным спецификатором типа, который может быть использован для представления нового имени класса.

$3.1/4 Объявления и определения [basic.def]

[Примечание. Имя класса также может быть объявлено неявным спецификатором разработанного типа ([dcl.type.elab]). - конечная нота]

$9.1/2 Имена классов [class.name]:

Объявление, состоящее исключительно из идентификатора ключа класса; является либо переоформление имени в текущем поле или вперед объявление идентификатора в качестве имени класса. Он вводит класс name в текущую область.

$3.4.4/2 Специфичные спецификаторы типов [basic.lookup.elab]:

или если специфицированный спецификатор типа появляется в объявлении с форма:

class-key attribute-specifier-seqopt identifier ; 

специфицированный спецификатор типа - это объявление, которое вводит class-name, как описано в [basic.scope.pdecl].

$3.3.2/7 Точка декларации [basic.scope.pdecl]:

если специфицированный спецификатор типа используется в описании-спецификаторе-seq или параметр-объявление-предложение функции, определенной в области пространства имен, идентификатор объявляется как имя класса в пространстве имен, содержит объявление;

Для struct tm timeval, используемого в качестве объявления параметра функции, поскольку <time.h> не включен и класс класса tm по-прежнему отсутствует, класс tm будет объявлен в текущей области (т.е. namespace xm), затем xm::tm будет объявлен вперед.