2016-04-06 2 views
1

Я ищу способ автоматического определения уникального имени объекта/символа на основе типа, как показано в следующем примере, где MEMBER(TypeName) - это что-то (макрос/whatever ...), который представляет/расширяется до уникального идентификатора объекта, идентификатор которого определяется от TypeName.Как автоматически определить уникальный объект/имя символа на основе типа

class A { int i; }; 
class B { int i; }; 
class X 
{ 
    A MEMBER(A); 
    B MEMBER(B); 
    X() 
    { 
     MEMBER(A).i = 1; 
     MEMBER(B).i = 2; 
    } 
}; 

Я первый попытался использовать следующий простой макрос, чтобы сделать это:

#define MEMBER(TypeName) m_ ## TypeName 

, который прекрасно работает, до тех пор, как TypeName не полное имя, такое как NameSpace::Type; поэтому я все еще ищу решение, работающее с полностью квалифицированными именами типов.

Примечание1: синтаксис для определения и использования членов класса X, описанных выше, предоставляется только для уточнения моих потребностей; решение может включать совершенно иной способ определения и использования членов.
Примечание2: члены класса X не должны быть статическими.
Примечание3: доступ к членам класса X должен быть быстрым; предпочтительным является решение времени компиляции.
Примечание4: класс X не может содержать более одного элемента того же типа.

Спасибо за помощь.

+0

как об использовании 'станд :: tuple'? если вы генерируете имена, основанные на типах, то это означает, что ваши члены класса имеют уникальные типы. Если это так, то' станд :: кортеж :: получить 'идеально подходит для вас. Макросов препроцессора следует избегать в C++, если он не может быть на C++. – mariusm

+0

@mariusm: Звучит как хорошее решение моей проблемы. Я попробую и отправлю отзыв. Пожалуйста, разместите свое решение в качестве ответа, чтобы он мог получать голоса. Спасибо за Ваш ответ. – shrike

+0

@mariusm: после быстрого поиска std :: tuple может быть хорошим решением, если std :: tuple :: get разрешен во время компиляции (штраф за исполнение не будет приемлемым, если нет); можете ли вы сказать мне, разрешено ли это во время компиляции или нет? Благодарю. – shrike

ответ

2

Если имена хлопот, то давайте избавимся от них полностью с помощью кортежей:

#include <tuple> 

class A: public std::tuple<int>{}; 
class B: public std::tuple<int>{}; 

class X: std::tuple<A,B> { 
public: 
    X() { 
    std::get<int>(std::get<A>(*this)) = 1; 
    std::get<int>(std::get<B>(*this)) = 2; 
    } 
}; 
+0

только недостаток, который я вижу, вам все равно нужно назвать типы ...;) – BeyelerStudios

+0

На самом деле классы A & B намного сложнее, чем представлены выше, поэтому я должен держать их такими, какие есть. Тем не менее, я определенно могу использовать std :: tuple для хранения экземпляров A & B в X. Что-то вроде class X { std::tuple inst; }. Затем я могу получить доступ к экземплярам в X, используя std :: get (inst) (который разрешен во время компиляции и, таким образом, быстро, по мере необходимости). Теперь я должен решить новую проблему: A & B не имеет конструктора по умолчанию. Большое спасибо за ваше решение, это выглядит очень хорошо (если не лучшим). – shrike

+1

@BeyelerStudios существует также 'std :: get ()' вариант с N как const integer, который обеспечивает доступ к каждому отдельному полю в кортеже. – mariusm

0

Вы можете использовать __LINE__ Marco в составе смеси в вашем Марко:

__LINE__ Этот макрос раскрывается в номер текущей строки ввода, в виде десятичной целой константы. Хотя мы называем это предопределенным макросом, это довольно странный макрос, поскольку его «определение» изменяется с каждой новой строкой исходного кода.

+0

Я думаю, что это не сработало бы, если бы две декларации были в одной строке – atturri

+0

Мне кажется, что такого требования нет, но '__LINE__' поддерживается каждый, потому что это стандартный марко. – AnatolyS

+0

Это решение действительно позволяет определить уникальное имя символа при определении экземпляра (пока 2 определения не находятся в одной строке), но главная проблема заключается в следующем: как получить доступ к членам позже? (как в конструкторе X() в примере выше). В любом случае спасибо за ваш ответ. – shrike

1
#define DECL_NMEMBER(NameSpace, TypeName) NameSpace::TypeName m_##NameSpace##_##TypeName; 
#define NMEMBER(NameSpace, TypeName) m_##NameSpace##_##TypeName 
#define DECL_MEMBER(TypeName) DECL_NMEMBER(, TypeName) 
#define MEMBER(TypeName) NMEMBER(, TypeName) 

namespace N 
{ 
class A { public: int i; }; 
class B { public: int i; }; 
} 

class C { public: int i; }; 

class X 
{ 
    DECL_NMEMBER(N, A)  // N::A 
    DECL_NMEMBER(N, B)  // N::B 
    DECL_MEMBER(C)   // C 
    DECL_NMEMBER(std, string) // std::string 
    DECL_MEMBER(wstring) // std::wstring (using namespace std) 
    X() 
    { 
     NMEMBER(N, A).i = 1; 
     NMEMBER(N, B).i = 2; 
     MEMBER(C).i = 5; 
     NMEMBER(std, string) = "test"; 
     MEMBER(wstring) = L"test2"; 
    } 
}; 

но для некоторых типов, таких как vector<T> вам нужно сделать некоторые дополнительные макросы ( нет идеального решения я думаю

+0

Спасибо, это приемлемое решение для моих текущих потребностей. Пока я не буду работать с шаблонами, я собираюсь использовать ваше решение. Спасибо за Ваш ответ. – shrike

Смежные вопросы