I was searching for template code that answers the question "does class T have member X?". There are some solutions on the web that employ SFINAE (for example, see How to detect whether there is a specific member variable in class?), but they all have the disadvantage that the member name X is hard coded in the solution. So I created a macro DECL_HAS_MEMBER(member_name) which declares the required template classes that check for member "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;
Now I can use the following code:
DECL_HAS_MEMBER(test)
...
bool has_test = has_member_test_v<MYCLASS>;
(Side note: In fact, I refined this code a bit to find out whether "test" is a static integral data member.)
The problem arises when I have two "DECL_HAS_MEMBER(test)" calls in the same translation unit, for example via different included header files. The MSVC compiler issues these error messages:
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
While I understand that the compiler doesn't want to see two (although identical) definitions of a template or a variable, I don't see how to solve the problem. An include guard clearly won't help because it is not the header file about which the compiler complains.
Any ideas?