Внешняя функция в классе

#c #visual-studio-2013 #icc

# #c #visual-studio-2013 #icc

Вопрос:

Мой простой код выглядит так:

a.cpp:

 #include <iostream>

namespace asd
{
    class B
    {
    public:
        void ss()
        {
            extern int i;
            std::cout << i;
        }
    };
}

int main()
{
    asd::B e;
    e.ss();
}
 

b.cpp:

 int i = 4;
 

Подходит ли этот код для стандарта или нет?
Visual Studio компилирует его без ошибок, но компилятор Intel C говорит:
неразрешенный внешний символ «int asd::i» (?i@asd@@3HA)

Для большего удовольствия, если я изменю b.cpp чтобы:

 namespace asd
{
    int i = 4;
}
 

Затем Visual Studio C 2013 говорит:
неразрешенный внешний символ «int i» (?i @@3HA)

Но компилятор Intel C говорит, что все в порядке 🙂 Какова правильная версия этого кода, если я хочу иметь эту внешнюю функцию в функции-члене класса (это законно?)?

Редактировать: наилучшие результаты, когда мы меняем b.cpp чтобы:

 namespace asd
{
    int i = 4;
}
int i = 5;
 

Visual c печатает 5, компилятор intel 4 🙂

Комментарии:

1. Что это за таинственный «другой компилятор»?

2. Я сравнил результаты с компилятором Intel. Gcc я не тестировал.

3. Пожалуйста, покажите свой B.cpp , он компилируется с помощью gcc для меня.

4. Пока области пространства имен для определения и объявления совпадают, все должно работать. Смотрите ответ @dasblinkenlight

5. Хорошо, я сообщил об ошибке: connect.microsoft.com/VisualStudio/feedback/details/909772 /…

Ответ №1:

Законно объявлять extern или static переменную внутри любой функции. Ваше исправление b.cpp того, где вы помещаете пространство имен вокруг определения этого extern , тоже является правильным исправлением.

Visual Studio C 2013 жалуется на имя вне asd пространства имен (проверьте деманглер, чтобы увидеть, что представляют эти дополнительные символы вокруг имени i ). Это неверно, потому что объявление помещается i в пространство asd имен .

Стандарт C иллюстрирует это в разделе 3.5.7. Он использует extern функцию в качестве примера, но он иллюстрирует правило размещения имени во вложенном пространстве имен.

 namespace X {
    void p() {
        q(); // error: q not yet declared
        extern void q(); // q is a member of namespace X
    }
    void middle() {
        q(); // error: q not yet declared
    }
    void q() { /* ... */ } // definition of X::q
}
void q() { /* ... */ } // some other, unrelated q
 

Комментарии к строкам 4, 9 и 11 показывают, что имя, объявленное extern внутри функции-члена, должно быть помещено во включающее пространство имен. Это хороший, автономный тестовый пример, иллюстрирующий ошибку в компиляторе Microsoft.

Ответ №2:

Похоже, Visual Studio ошибается.

Это то, что я нашел в проекте стандарта:

3.3.2/10

Объявления функций в области блока и объявления переменных со extern спецификатором в области блока относятся к объявлениям, которые являются членами окружающего пространства имен, но они не вводят новые имена в эту область.

Сказав это, я бы переместил extern объявление из функции в пространство имен, чтобы посмотреть, имеет ли это какое-либо значение.

 namespace asd
{
    extern int i;
    class B
    {
    public:
        void ss()
        {
            std::cout << i;
        }
    };
}