我想编写一个 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>;
};
但是,这些似乎都没有按照预期的方式工作:
- 第一个案例有错误
Constraint variable 'n' cannot be used in an evaluated context
. - 第二种情况编译没有任何错误,但是
notifiable<notifiable_type, categories>
不满意。
有人可以帮我澄清一下吗?我想写的可能吗?
最佳答案
你与这个非常接近(我继续将 std::is_enum<E>::value
更改为 std::is_enum_v<E>
,并且还减少了类型的名称,因为它们很长并且几乎彼此相同,这让我感到困惑位):
template<typename T, typename E>
concept notifiable =
std::is_enum_v<E>
&& requires(T t, const E n) {
{ t.template notification<n>() } -> std::same_as<void>;
};
问题是你不能使用n
就像那样,因为它需要是一个常数,但事实并非如此。因此,解决方案是不要发明 E
类型的变量而是发明 E
类型的值 。而且,好吧,0
与任何值一样好:
template <typename T, typename E>
concept notifiable = std::is_enum_v<E>
&& requires(T t) {
{ t.template notification<E{}>() } -> std::same_as<void>;
};
自 E
是一个枚举,我们知道E{}
已验证。不需要declval
,这同样与您原来的方法存在相同的问题:它不是一个常量,但它需要是一个常量。
一个类似的解决方案,尽管更冗长且通常更奇怪,是:
template <typename T, typename E>
concept notifiable = std::is_enum_v<E>
&& requires(T t, std::integral_constant<E, E{}> n) {
{ t.template notification<n>() } -> std::same_as<void>;
};
现在,这个有效,因为 integral_constant<T, V>
constexpr 可转换为 T
值(value)V
。这种转换在很多情况下都非常有用,因为它允许以保留常数的方式近似地将常量作为函数参数传递。
但在这种情况下这是没有意义的,所以我只是为了说明而展示它。
请注意,这仍然是有限的,我们只是专门检查 E{0}
有效 - 不是任何E
有效(我们通常不能这样做)。这可能已经足够好了,尽管如果您遇到 T::notification
的情况,您可能会得到假阴性结果。对其 E
有额外的限制.
关于c++ - 我可以编写一个需要函数模板的 C++ 概念吗?必须向该函数模板提供一些枚举值作为模板参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75818173/