класс признаков, пространство имен и прямое объявление - PullRequest
0 голосов
/ 18 января 2019

В настоящее время у меня проблемы с использованием пространств имен с классами черт. Вот моя предварительная структура кода:

namespace project {

namespace internal {
template<typename T> struct traits;

} // internal

namespace moduleA {

namespace internal {

class AImpl {

using some_typeA = traits<A>::some_type;
using some_typeAImpl = traits<AImpl>::some_type;
// where to put the traits specialization?? How the forward declaration could be done?

};

} // internal

class A {

A(): imp(new internal::AImpl()) {}
private:
    internal::AImpl* imp;
};

} // moduleA

} // project

Вот мои вопросы, и я ищу предложения, чтобы этот код лучше соответствовал установленным правилам и рекомендациям:

  1. Я определяю два внутренних пространства имен, ::project::internal и ::project::moduleA::internal, это плохая практика? Меня беспокоит то, что на двух уровнях пользователю будет проще просматривать документацию из doxygen, поскольку все связанные с модулем A вещи, как moduleA :: internal, так и нет, сгруппированы вместе.
  2. Поскольку moduleA::internal::AImpl зависит от самого класса черт traits<AImpl>, а мои шаблоны черт находятся в ::project::internal, поэтому я должен (1) определить шаблон черт в moduleA::internal и специализировать его; (2) определить специализацию черт в ::project::internal. Для этого мне нужно заранее объявить AImpl. Как именно это должно быть сделано для каждого случая (1) или (2)? Означает ли это, что я должен написать код, подобный этому:
namespace project {
namespace moduleA {class A;}
namespace internal {
template<>
struct traits<module::A> {};
}
namespace moduleA {
... // more code
}
}

Похоже, я слишком часто использую предложения namespace {}.

  1. Аналогично 2, module::internal::AImpl зависит от traits<A>, опять же мне нужно переслать объявление A, поэтому та же проблема.

Я бы очень признателен вам за помощь, спасибо!

1 Ответ

0 голосов
/ 18 января 2019

Вместо использования шаблонов классов для признаков в C ++ 11 вы можете использовать объявления функций (определение не требуется). Функции можно найти, используя поиск имени в зависимости от аргумента , так что вы можете специализировать черты для вашего класса в том же пространстве имен, где объявлен ваш класс.

Это полностью устраняет необходимость закрывать пространство имен вашего класса, открывать пространство имен признаков, специализировать черту для вашего класса, используя его полностью определенное имя, закрывать пространство имен признаков, заново открывать пространство имен вашего класса. А также устраняет необходимость включать объявление основного шаблона.

Пример:

#include <type_traits>

template<class T> struct Type {};

template<class T>
void trait_of(Type<T>); // Generic trait version.

namespace N {
struct A;
int trait_of(Type<A>); // Trait specialisation for A.
} // N

int main() {
    using trait_of_a = decltype(trait_of(Type<N::A>{})); // trait_of is found using ADL.
    static_assert(std::is_same<int, trait_of_a>::value, "");
}

Тип возвращаемого значения функции trait может быть контейнером нескольких типов, например ::1100*.

template<class T>
void more_traits(Type<T>); // Generic trait version. Must be specialized.

namespace N {
struct MoreTraitsOfA {
    using type_X = ...;
    using type_Y = ...;
};
MoreTraitsOfA more_traits(Type<A>); // Trait specialisation for A.
} // N

using MoreTraits = decltype(more_traits(Type<N::A>{})); 
using type_X = MoreTraits::type_X;
using type_Y = MoreTraits::type_Y;
...