Удобный способ использования пространства имен в деталях реализации (библиотека только для заголовков)? - PullRequest
0 голосов
/ 20 июня 2020

Итак, я работаю над этой библиотекой (только заголовок), которая имеет несколько модулей и использует встроенное пространство имен для управления версиями. Таким образом, полностью определенные имена могут иногда становиться немного длиннее. Я хотел бы использовать «using namespace x» в качестве детали реализации внутри (встроенных) детальных пространств имен, но это загрязняет внешнее пространство имен.

См. Пример кода на godbolt: https://godbolt.org/z/pdSXrs

Я нашел два обходных пути (см. Ссылку на Godbolt), которые делают то, что я хочу, но кажутся слишком сложными. Есть ли более простой способ сделать это? Должен ли я просто ввести все полные имена (и сохранить сообщения об ошибках в чистоте)? Я хотел бы знать, каковы лучшие практики для «более сложных» конструкций пространства имен.

Изменить: добавлен код, как предложено

// think of these as in header files

namespace mylib{
    namespace module0{
        inline namespace mystuff{
            // this constant conceptually belongs to module 0 but might be used as an
            // implementation detail in other modules
            int myconst = 42;
        }
    }
}

namespace mylib{
    namespace module1{
        // I would like to use this, but pollutes mylib::module1 namespace
        inline namespace detail1{
            using namespace mylib::module0::mystuff;
            struct foo1{
                int operator()(){
                    return myconst;
                }
            };          
        }
    }
}

namespace mylib{
    namespace module2{
        inline namespace detail1{
            // this works but seems overly complicated
            namespace more_detail{
                using namespace mylib::module0::mystuff;
                struct foo2{
                    int operator()(){return myconst;}
                };
            }
            // might be very cumbersome to use if lots of classes
            using more_detail::foo2;
        }
    }
}

namespace mylib{
    namespace module3{
        inline namespace detail1{
            // is this a good way to namespace a library...?
            namespace more_detail{
                using namespace mylib::module0::mystuff;
                // not enough namespaces yet?!
                namespace devil_of_details{
                    struct foo3{
                        int operator()(){return myconst;}
                    };
                }
            }
            // useable for lots of classes/types in that namespace... but really?!
            using namespace more_detail::devil_of_details;
        }
    }
}

// think of this as myprogram.cpp including the headers
#include <iostream>

int main(){

    // polluted namespace. I can probably live with it, but it's not ideal
    // constant should only be visible in module0
    int x1 = mylib::module1::myconst;
    std::cout << x1 << std::endl;
    // ok
    int x0 = mylib::module0::myconst;

    // this is what I ideally want, i.e. not polluting module2 namespace
    int x2_error = mylib::module2::myconst;

    // this is what I ideally want, i.e. not polluting module3 namespace
    int x3_error = mylib::module3::myconst;

    // normal usage in cpp file
    using namespace mylib::module2;
    int x2 = foo2{}();
    std::cout << x2 << std::endl;

    // ok
    using namespace mylib::module0;
    std::cout << myconst << std::endl;
}

1 Ответ

1 голос
/ 20 июня 2020

Я бы предложил псевдонимы пространств имен.

namespace mylib{
    namespace module1{
        namespace details0 = module0::mystuff;
    }
}

Хотя это делает другие пространства имен видимыми, на самом деле он не импортирует символы, как это делает using, то есть mylib::module1 не имеет myconst member.

Также обратите внимание, что если пространство имен, которое вы в настоящее время определяете, является частью mylib, нет необходимости иметь mylib как часть имени. Даже если вы закроете mylib, затем снова откройте его.

То есть:

namespace mylib {
    namespace part1 { /* ... */ }
}
namespace mylib {
    namespace part2 { namespace p1 = part1; }
}

p1 будет относиться к mylib::part1, если вы не укажете, что это - полное имя (::part1).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...