标题是非常自我解释。以下是我的情况:
#include <type_traits>
class C1{
enum{
c1 = 3
}
}
class C2{
enum{
c2 = 10
}
}
template<class C>
class C3{
void do_this();
void do_that();
void foo(){
if constexpr(std::is_enum<C::c1>::value){
do_this();
}
if constexpr(std::is_enum<C::c2>::value){
do_that();
}
}
}
如果我试着编译它,我会得到错误
error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::is_enum’
note: expected a type, got ‘typename C::c1’
error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::is_enum’
note: expected a type, got ‘typename C::c2’
所以我的问题是:是否可以将std::is_enum
与未命名的enum
s一起使用?
4条答案
按热度按时间ego6inou1#
完全可以将
std::is_enum
与未命名的枚举一起使用。在当前的实现中,只有两个问题需要解决:
std::is_enum<C::c1>::value
-C::c1
是数据成员,但std::is_enum
需要类型模板参数。=>这里需要使用
decltype(...)
,例如std::is_enum<decltype(C::c1)>::value
C
没有名为c1
的成员,则C::c1
将导致替换失败。解决这个问题的唯一方法是在替换失败不会导致程序格式不正确的情况下执行此操作。
因此,您可以使用SFINAE或(如果C20可用)requires-expression。
在C20中,这是可行的:
godbolt example
如果
C::c1
和C::c2
互斥(即每个类C
都有c1
或c2
,或者两者都没有-但永远不会同时有c1
和c2
),您可以考虑使用尾随的requires-clauses来重载foo
。godbolt example
如果C++20不可用,则需要使用SFINAE,这有点麻烦:
godbolt example
lnvxswe22#
C++11使用SFINAE
您可以使用
decltype
获取与c1
和c2
关联的类型,然后使用 SFINAE,如下所示。C++11 Demo:另请参阅使用
std::enable_if_t
、std::is_same_v
和std::is_enum_v
的C++ 17 demo版本。C++20使用概念
C++ 20 demo
41zrol4v3#
你可能应该给它们起相同的名字,这样模板就可以同时使用它们:
ff29svar4#
也有很好的答案,但我会给予C++20的另一个变体:
这使用了一个嵌套的需求,而不是像@Turtlefight的答案中那样使用了一个带有类型约束的复合需求。如果替换到表达式中导致无效的类型或表达式,则嵌套要求失败,如果表达式不是计算为
true
的bool
类型的常量表达式,则嵌套要求也失败。但这在功能上应该是相同的。decltype
中的附加括号是必要的,另一个答案中使用的复合语句也隐含地使用decltype
来确定表达式的类型。如果没有它,
decltype
将为枚举类型的数据成员(而不是枚举器的名称)生成非引用类型并成功,例如。将成功进行
c1
和c2
的测试,而不是仅成功进行c2
的测试。