Когда полезно использовать namespace :: function ()? - PullRequest
0 голосов
/ 17 мая 2018

Пример одного файла

Вот простая программа, использующая пространства имен.

#include <iostream>

namespace foo {
    void hello();
}

void foo::hello() {
    std::cout << "hello\n";
}

void foo::hello(); // Why is this syntax allowed? When is it useful?

int main() {
    foo::hello();
}

Эта программа прекрасно компилируется и выдает ожидаемый результат.

$ ./a.out
hello

Я хочу знать, когда полезна декларация void foo::hello();? В этой программе эта декларация явно избыточна. Но поскольку этот синтаксис существует, это должно быть полезно в каком-то другом сценарии?

Пример с двумя файлами

Вот пример, который показывает, что само по себе объявление void foo::hello(); бесполезно.

// foo.cpp
#include <iostream>

namespace foo {
    void hello();
}

void foo::hello() {
    std::cout << "foo::hello\n";
}
// main.cpp
void foo::hello(); // This does not work!

int main()
{
    foo::hello();
}

Попытка скомпилировать два вышеуказанных файла приводит к следующим ошибкам:

$ clang++ foo.cpp main.cpp
main.cpp:1:6: error: use of undeclared identifier 'foo'
void foo::hello();
     ^
main.cpp:5:5: error: use of undeclared identifier 'foo'
    foo::hello();
    ^
2 errors generated.

Единственный способ исправить main.cpp в приведенном выше примере - это объявление namespace:

// main.cpp - fixed
namespace foo {
    void hello();
}

void foo::hello(); // But now this is redundant again!

int main()
{
    foo::hello();
}

Так что после того, как мы получим этот код для правильной компиляции, объявление void foo::hello(); снова кажется излишним. Есть ли сценарий, в котором такая декларация сыграла бы полезную роль?

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

В большинстве случаев в C ++ для всего, что может быть объявлено без определения или может быть полностью определено, объявление или определение этой вещи могут появляться во всех одинаковых контекстах. Так что это, вероятно, просто способ сохранить последовательность шаблонов.

Стандарт C ++ не старается запрещать вещи, которые являются логическим следствием его других правил, но просто бесполезны, при условии, что достаточно ясно, что произойдет, если кто-то сделает это в любом случае. Если бы это добавило эти ограничения, это добавило бы дополнительную работу авторам компилятора без реальной выгоды.

0 голосов
/ 17 мая 2018

С [basic.def] / 1

Декларация может вводить одно или несколько имен в единицу перевода или переименовывать имена, введенные предыдущими декларациями. Если это так, в объявлении указывается толкование и атрибуты этих имен.

Что позволяет код, подобный этому

#include <iostream>

void foo();
void foo();
void foo();
void foo();
void foo();

int main()
{
    foo();
}

void foo() { std::cout << "foo()"; }

Быть действительным. Использование нескольких объявлений функции не повредит, если у нас только одно определение, это не вызовет проблемы.


Другой пример: у вас есть глобальная функция, которую вы хотите дружить с несколькими классами. Вы бы включили этот прототип функции в каждый заголовок класса, чтобы вы могли дружить с ним, а затем включили бы все эти заголовки классов в ваш основной исходный файл. Так

A.h
void foo();
struct A { friend void foo(); }

B.h
void foo();
struct B { friend void foo(); }

main.cpp
#include "A.h"
#include "B.h"

...

и это будет преобразовано в

main.cpp
void foo();
struct A { friend void foo(); }

void foo();
struct B { friend void foo(); }

...

Итак, мы бы хотели, чтобы это было законно.

...