C ++, использующий пространства имен, чтобы избежать длинных путей

StackOverflow https://stackoverflow.com/questions/708089

  •  22-08-2019
  •  | 
  •  

Вопрос

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

Файл A.h,

namespace Test
{
    class A
    {
        public:
            static int foo() { return 42; }
    };
}

Файл main.cpp,

#include <iostream>

#include "A.h"

using namespace std;
using namespace Test::A;

int main()
{
    cout << foo() << endl;

    return 0;
}

Компилятор дает мне:

main.cpp:6: error: ‘A’ is not a namespace-name
main.cpp:6: error: expected namespace-name before ‘;’ token
main.cpp: In function ‘int main()’:
main.cpp:10: error: ‘foo’ was not declared in this scope

Возможно ли сделать то, что я пытаюсь сделать, не набирая текст A::foo?

Это было полезно?

Решение

Обойти это невозможно, вам нужно указать имя класса для статических методов.

using namespace Test;

Тогда:

int answerToEverything = A::foo();

Другие советы

В C ++ вы /особенно/ должны внимательно читать сообщения об ошибках компилятора.

Обратите внимание, что первой ошибкой было "ошибка:‘A’ - это не имя пространства имен".Это правда, A - это имя класса.

using namespace Foo; // brings in  all of foo;
using Bar::Baz // brings in only Baz from Bar

Вы хотите написать:

using Test::A;

Это делает две хорошие вещи:это дает вам возможность использовать, и это не приводит ко всему остальному тестированию, что тоже хорошо, потому что вы должны вводить только то, что вам нужно, чтобы случайно не зависеть от чего-то, от чего вы не осознаете, что зависите.

Однако, поскольку foo является статичным в A, вам все равно придется явно ссылаться на A::foo .(Если только вы не сделаете что-то вроде написания бесплатной функции, которая пересылает в ::foo;в общем, это плохая идея, если вы делаете это только для того, чтобы сэкономить время на вводе текста.)

Некоторые могут посоветовать вообще не использовать объявления using, вместо этого полностью уточняя все имена.

Но это (цитируя Страуструпа) "утомительно и подвержено ошибкам", и это мешает рефакторингу:скажите, что вы полностью квалифицируете каждое использование class FooMatic::Stack, а затем руководство настаивает, непосредственно перед тем, как вы собираетесь приступить к производству, чтобы вы использовали очень похожий класс Stack от BarMatic, потому что barMatic только что выкупила вашу компанию.

Если бы у вас была полная квалификация везде, вы бы много занимались греппингом, надеясь, что ваше регулярное выражение было правильным.Если вы использовали объявление using, вы можете просто внести исправление в свой (надеюсь, общий) заголовочный файл.Таким образом, объявление using очень похоже на "typedef int ourInt;" или константу манифеста или const:"const int FOO = 1;", в том смысле, что он предоставляет одно место для изменения чего-то, что упоминается во многих местах.Полная квалификация пространства имен при каждом использовании лишает его этого преимущества.

И наоборот, если бы вы использовали директиву using и ввели все пространство имен FooMatic, ваш grep мог бы быть еще сложнее, если бы, скажем, руководство настаивало на BarMatic::Foo, но вам все равно пришлось использовать FooMatic:Baz, эквивалент BarMatic для Baz по какой-либо причине непригоден.

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

Нет, невозможно сделать то, что вы пытаетесь сделать, каким-либо элегантным способом.Самое близкое, что вы сможете сделать, - это создать макрос или встроенную функцию, которая делегирует полномочия вашей функции.Однако обе эти альтернативы довольно уродливы, поэтому я не собираюсь публиковать какие-либо примеры кода.Просто прикусите язык и укажите полное имя или реорганизуйте свой код так, чтобы статические методы были просто глобальными функциями.

Не будьте сторонником "использования пространства имен".Используйте эти пространства имен!

std::cout << Test::A::foo() << std::endl;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top