«имеет ли класс T член X»: шаблон класса уже определен - PullRequest
0 голосов
/ 10 марта 2019

Я искал код шаблона, который отвечает на вопрос "имеет ли класс T член X?".В Интернете есть некоторые решения, в которых используется SFINAE (например, см. Как определить, существует ли конкретная переменная-член в классе? ), но у всех них есть недостаток, заключающийся в том, что имя члена X жестко закодировано.в решении.Поэтому я создал макрос DECL_HAS_MEMBER (member_name), который объявляет необходимые классы шаблонов, которые проверяют член "member_name":

#define DECL_HAS_MEMBER(member_name) \
template<typename T, typename = void> struct has_member_##member_name : std::false_type {}; \
template<typename T> \
struct has_member_##member_name<T, decltype((void)T::member_name, (void)0)> : std::true_type {}; \
template<typename T> constexpr auto has_member_##member_name##_v = has_member_##member_name<T>::value;

Теперь я могу использовать следующий код:

DECL_HAS_MEMBER(test)
...
bool has_test = has_member_test_v<MYCLASS>;

(Примечание: фактически, я немного усовершенствовал этот код, чтобы выяснить, является ли «test» статическим целочисленным элементом данных.)

Проблема возникает, когда у меня два вызова «DECL_HAS_MEMBER (test)» в одном и том жеблок перевода, например, через различные включенные заголовочные файлыКомпилятор MSVC выдает следующие сообщения об ошибках:

warning C4348: 'has_member_test': redefinition of default parameter: parameter 2
error C2953: 'has_member_test': class template has already been defined
error C2976: 'has_member_test': too few template arguments
error C2086: 'const auto has_member_test_v': redefinition

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

Есть идеи?

1 Ответ

0 голосов
/ 10 марта 2019

Есть, конечно, несколько вариантов.Вот два:

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

2) вы выполняете DECL_HAS_MEMBER внутри класса, который вы хотите протестировать.В этом сценарии все проверки находятся в отдельных пространствах имен классов, и конфликтов не будет.

...