【发布时间】:2019-03-10 09:58:16
【问题描述】:
我正在寻找可以回答“T 类是否有成员 X?”问题的模板代码。网络上有一些使用 SFINAE 的解决方案(例如,请参阅 How to detect whether there is a specific member variable in class?),但它们都有一个缺点,即成员名称 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
虽然我知道编译器不想看到模板或变量的两个(尽管相同)定义,但我不知道如何解决这个问题。包含保护显然无济于事,因为它不是编译器抱怨的头文件。
有什么想法吗?
【问题讨论】:
-
你可能想要
std::experimental::is_detected。 -
@HolyBlackCat,我的印象是 MS 编译器还不支持它。除此之外,我想你是对的......
-
将每个
DECL_HAS_MEMBER放在不同的detail命名空间中? -
@Oktalist,这是个好主意。我玩过它 - 当我在 every DECL_HAS_MEMBER 周围使用命名空间时,它似乎可以工作:-)
-
您仍然可以重写
std::experimental::is_detected(可能还有一些依赖项(如琐碎的std::void_t))。没那么长。
标签: c++ templates sfinae typetraits