Потому как в первом случае из namespace'а берется имя класса, а во втором не понятно это определение функции из namespace'а или просто свободная функция. Вродь так. Поправьте меня если я не прав
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>А почему ты решил, что нельзя?
Потому что компилироваться — компилируется, но при попытке вызова bar::baz() — не линкуется (не находит bar::baz()). Похоже, что baz() в Baz.cpp рассматривается как определение еще одной свободной функции. Почему компилятор не рассматривает определение baz() в baz.cpp как определение bar::baz()?
If a shark stops swimming, it will die. Don't stop swimming, Mr. Mulder.
Every epic equalizer is iso (c)
K>>нельзя?
WD>Потому как в первом случае из namespace'а берется имя класса, а во втором не понятно это определение функции из namespace'а или просто свободная функция. Вродь так. Поправьте меня если я не прав
Надо так:
// Baz.hnamespace bar
{
void baz();
}
// Baz.cpp#include"Baz.h"namespace bar
{
void baz()
{
}
}
// или
bar::baz()
{
}
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>А почему ты решил, что нельзя?
Нельзя, потому что компилер не знает чего от него хотят: то ли функцию из нэймспейса определить, то ли новую написать.
Код с классом тоже компилиться не будет, если такой же объявить вне нэймспейса.
Здравствуйте, Максим2006, Вы писали:
М>Нельзя, потому что компилер не знает чего от него хотят: то ли функцию из нэймспейса определить, то ли новую написать. М>Код с классом тоже компилиться не будет, если такой же объявить вне нэймспейса.
В том-то и дело, что пример с функциями — компилируется, но не линкуется, а пример с классами — не скомпилируется.
If a shark stops swimming, it will die. Don't stop swimming, Mr. Mulder.
Every epic equalizer is iso (c)
Здравствуйте, kwas, Вы писали:
K>Здравствуйте, Максим2006, Вы писали:
М>>Нельзя, потому что компилер не знает чего от него хотят: то ли функцию из нэймспейса определить, то ли новую написать. М>>Код с классом тоже компилиться не будет, если такой же объявить вне нэймспейса.
K>В том-то и дело, что пример с функциями — компилируется, но не линкуется, а пример с классами — не скомпилируется.
это от того, что локальное объявление перекрывает объявление более высокого уровня. То есть эта функция скомпилировалась как локальная для этого файла, а значит, функция из нэймспейса осталась не определённой, отсюда и ошибка линковки.
Понаписал много лишнего, т.к. сам с некоторыми моментами хотел разобраться, может кому-то эта писанина тоже пригодатся. Если кому лень читать, вывод находится в самом конце.
Для начала немного теории:
scope и declarative region (3.3/1):
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity. In general, each particular name is valid only within some possibly discontiguous portion of program text called its scope.
Еще относительно деклараций (3.3/3):
The names declared by a declaration are introduced into the scope in which the declaration occurs
using-directive (7.3.4/1):
A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.
То есть, имена, вводимые using-directive видны как декларации только в ходе поиска имен.
Теперь рассмотрим случай со свободными функциями.
namespace test
{
void foo( ); //1
}
void foo( ) //2
{}
int main( void )
{}
В данном случае у нас декларация 1 вводит имя foo в scope пространства имен test, а декларация 2, которая является определением (8.4), вводит имя foo в global scope (3.3.5/3). Поскольку декларации 1 и 2 находятся лексически в разных scope, они относятся к различным функциям (13.2/1):
Two function declarations of the same name refer to the same function if they are in the same scope and have equivalent parameter declarations
Вместо этого после декларации 2 имя foo из global scope скрыто именем foo из namespace test при поиске имен в namespace test (3.3.7/1):
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class
namespace test
{
void foo( ); //1
}
using namespace test;
void foo( ) //2
{}
int main( void )
{}
В виду указанной особенности using-directive в данном контексте она не может расцениваться как декларация foo, поэтому, как и в первом примере, декларации 1 и 2 никак не связаны.
Ради интереса, можно еще рассмотреть пример с using-declaration:
namespace test
{
void foo( ); //1
}
using test::foo;
void foo( ) //2
{}
int main( void )
{}
Этот код не корректен (7.3.3/11):
If a function declaration in namespace scope or block scope has the same name and the same parameter types as a function introduced by a using-declaration, and the declarations do not declare the same function, the program is ill-formed.
Кроме этого, существует еще возможность использовать квалификацию для определения функции вне пространства имен, где она объявлена (7.3.1.2/2):
Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.
(8.3/1):
A declarator-id shall not be qualified except for the definition of a member function (9.3) or static data member (9.4) outside of its class, the definition or explicit instantiation of a function or variable member of a namespace outside of its namespace, or the definition of a previously declared explicit specialization outside of its namespace, or the declaration of a friend function that is a member of another class or namespace (11.4). When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers, and the member shall not have been introduced by a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id.
Видимо, этот пункт можно рассматривать как исключение из (13.2/1).
Это можно проиллюстрировать следующим кодом:
Теперь относительно функций-членов.
В дополнение к уже процитированному (8.3/1) на всякий случай добавлю (9.3/2):
A member function may be defined (8.4) in its class definition, in which case it is an inline member function (7.1.2), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition. A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition.
и (9.3/5):
If the definition of a member function is lexically outside its class definition, the member function name shall be qualified by its class name using the :: operator.
Итого, наиболее существенным здесь является то, что при декларации функции с неквалифицированным declarator-id действует простое правило, основанное на лексическом расположении декларации в определенном scope, а при использовании квалифицированного declarator-id (в том числе out of class определения функций-членов), сам квалификатор является предметом поиска имен.