【问题标题】:"does class T have member X": class template has already been defined“类 T 是否有成员 X”:类模板已定义
【发布时间】: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


【解决方案1】:

当然有几种选择。这里有两个:

1) 您的宏为“测试”生成的代码当然适用于任何类。因此你真的只需要它一次。您可以在一个额外的包含文件中定义所有 DECL_HAS_MEMBER,将其包含在您要进行检查的位置并进行检查。

2) 您在要测试的类中执行 DECL_HAS_MEMBER。在这种情况下,所有检查都在单独的类命名空间中,不会发生冲突。

【讨论】:

  • 好主意!但是...... Re 1 - 当我将此宏放在许多人使用的头文件中时,我必须为所有可以想到的成员名称添加 DECL_HAS_MEMBER 宏...... Re 2 - 我问“你有成员的地方X" 在这样的模板声明中: template> { struct something {...};};这样就没有地方把测试放到一个类中了。
猜你喜欢
  • 2017-10-20
  • 1970-01-01
  • 2020-03-28
  • 2019-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多