Visual C: Ошибка в области имен или скрытая функция? - PullRequest
0 голосов
/ 03 октября 2019

Вам понадобятся три разных файла: header.h, source.cpp & main.cpp.

// header.h
#pragma once

namespace A
{

  namespace B
  {
    class C 
    {
    public: static void f();
    };

    void g();
  }

  using namespace B;
}

// source.cpp
#include "Header.h"

namespace A
{
  void C::f()
  {
    #pragma message( "Compiling " __FUNCTION__ )
  }

  void g()
  {
    #pragma message( "Compiling " __FUNCTION__ )
  }
}

// main.cpp
#include "Header.h"

int main()
{
  A::C::f();
  A::g();
}

Я не ожидал ошибки, вместо этого похоже, что класс и функция принадлежат разным пространствам имен, хотя объявлены и реализованы в одной и той же области :

1 > Source.cpp
1 > Compiling A::B::C::f
1 > Compiling A::g
1 > Generating Code...
1 > ConsoleApplication10.obj : error LNK2019 : unresolved external symbol "void __cdecl A::B::g(void)" ( ? g@B@A@@YAXXZ) referenced in function _main

Кодгенерируется инструментом.

Спасибо

Ответы [ 2 ]

3 голосов
/ 03 октября 2019

Когда вы делаете это:

  void C::f()
  {
    #pragma message( "Compiling " __FUNCTION__ )
  }

f здесь - это квалифицированное имя (квалифицированное C). Таким образом, C ++ должен выяснить, о чем C вы говорите. Для этого ему нужно посмотреть доступные неквалифицированные имена и найти в них идентификатор C. Поскольку вы находитесь в пространстве имен A, а в пространстве имен A было выгружено все пространство имен B, C преобразуется в A::B::C. И, таким образом, C::f становится A::B::C::f.

В отличие от этого, когда вы делаете это:

  void g()
  {
    #pragma message( "Compiling " __FUNCTION__ )
  }

g является неквалифицированным именем . Таким образом, это имя означает именно то, что оно говорит: имя g в текущем пространстве имен. Это объявления A.

using не изменяют текущее пространство имен;это только изменяет правила поиска имени для имен. Поскольку g - безусловное имя, искать нечего;Вы имели в виду A::g.

Это означает, что вы не определяете функцию A::B::g.

Итак, у вас есть заголовок с надписью "Я обещаю, что кто-тогде-то определит A::B::g, "но никто на самом деле не делает. source.cpp только определил A::g, который main.cpp не пытается вызвать (поскольку он не подозревает, что он существует).

Отсюда ошибка компоновщика.

2 голосов
/ 03 октября 2019

Во-первых, помните, что main.cpp ничего не видит из source.cpp, поэтому он не знает о действительной void A::g() функции, объявленной / определенной в ней!

Что main.cpp делает см. пространство имен A, которое using namespace B. Так, когда main.cpp вызывает A::g(), компилятор может только предполагать, что вы ссылаетесь на void A::B::g() - и, таким образом, помечает это как функцию для ссылки.

Но, как правильно диагностирует компоновщик, выне предоставили определение для этой функции - поэтому она не разрешена.

...