我想写一个C++概念,它用一个由枚举值专门化的函数模板来描述一个类型。例如,
enum class categories {
t1,
t2
};
struct notifiable_type {
template<categories category>
auto notification() {}
};
auto main() -> int {
notifiable_type().notification<categories::t1>();
}
到目前为止,我试过:
// 1
template<typename notifiable_t, typename notification_t>
concept notifiable = std::is_enum<notification_t>::value && requires(notifiable_t t, const notification_t n) {
{ t.template notification<n>() } -> std::same_as<void>;
};
// 2
template<typename notifiable_t, typename notification_t>
concept notifiable = std::is_enum<notification_t>::value && requires(notifiable_t t) {
{ t.template notification<std::declval<notification_t>()>() } -> std::same_as<void>;
};
然而,这两种方法似乎都没有以预期的方式工作:
1.第一种情况有错误Constraint variable 'n' cannot be used in an evaluated context
。
1.第二种情况编译后没有任何错误,但notifiable<notifiable_type, categories>
不满足。
有谁能为我澄清一下吗?我想写的东西可能吗?
2条答案
按热度按时间k3bvogb11#
您已经非常接近这个了(我继续将
std::is_enum<E>::value
更改为std::is_enum_v<E>
,并且还减少了类型的名称,因为它们非常长并且彼此几乎相同,这让我有点困惑):问题是你不能像这样使用
n
,因为它需要是一个常量,而它不是。所以解决方案是发明一个E
类型的 * 变量 *,而是发明一个E
类型的 * 值 *。而且,好吧,0
是一个很好的值:因为
E
是一个枚举,所以我们知道E{}
是有效的。不需要declval
,它也有与原始方法相同的问题:它不是一个常数,它必须是。一个类似的解决方案,虽然更冗长,而且通常更奇怪,应该是:
现在,这是可行的,因为
integral_constant<T, V>
是constexpr-可转换为值为V
的T
。这种转换在很多上下文中非常有用,因为它允许以保持常量的方式近似传递常量作为函数参数。但在这种情况下,它是毫无意义的,所以我只是为了说明它。
请注意,这仍然是有限的,我们只是检查特定的
E{0}
工作-而不是任何E
工作(我们通常不能这样做)。这可能已经足够好了,尽管你可能会得到假阴性,如果你有一些情况,比如T::notification
对其E
有额外的约束。de90aj5v2#
将显式整数值强制转换为枚举通常是不受欢迎的,但这可能是所有罪恶中最小的一种情况。而且,零和任何其他数字一样是强制转换的受害者。
Live Demo