c++ - 为什么不能将概念传递给模板元函数?
问题描述
考虑 Boost.MP11、Brigand 等库提供的任何常见类型级算法……例如:
template<typename... Args>
struct TypeList;
using my_types = TypeList<int, float, char, float, double>;
constexpr int count = boost::mp11::mp_count_if<my_types, std::is_floating_point>::value;
// this holds:
static_assert(count == 3);
请注意,std::is_floating_point
可以定义为:
template<typename T>
struct is_floating_point { constexpr bool value = __compiler_magic(T); };
同样,我们有这个std::floating_point
概念
template<typename T>
concept floating_point = requires (T t) { __other_compiler_magic(T); };
可悲的是,尽管有相似之处,但如果不为概念引入手动命名的包装器,似乎没有一种简单的方法可以编写这样的东西:
constexpr int count = boost::mp11::count_if<my_types, std::floating_point>::value;
我的问题是:为什么此时不能传递概念来代替类型?是缺乏标准化,还是这些库可以通过提供更多重载来解决?
看起来每个概念都必须包装在一个模板类型中,该类型只会在其模板参数上调用该概念。
从外部看,概念就像是域是 {set of types} -> bool 的元函数。编译器能够延迟将参数传递给“传统的”基于类型的元函数,例如std::is_floating_point
,为什么概念似乎不能发生相同的情况?
解决方案
字面上的答案是我们有模板模板参数但没有概念模板参数,因此您不能将概念作为模板参数传递。
另一个字面上的答案是,它从来都不是原始概念提案的一部分,也没有人努力建议它作为扩展(尽管我一直在收集用例)。
必须回答的一件事是依赖概念如何影响包容——因为目前概念的使用从来不是依赖的,所以弄清楚包容很简单(实际上,它仍然一点也不简单,但至少你需要的所有东西都是正确的那里)。但在这样的场景中:
template <template <typename> concept C, typename T>
requires C<T>
void foo(T); // #1
template <typename T>
void foo(T); // #2
可能如果#1
可行,您想说它是一个更好的候选者,而不是#2
因为它仍然受到限制而另一个没有。也许那是微不足道的。但是之后:
template <template <typename> concept C, typename T>
requires C<T>
void bar(T); // #3
template <OtherConcept T>
void bar(T); // #4
让我们说#3
并且#4
都是可行的,是否可以说哪个更好?我们通常说整个过载总是比不同的过载更好 - 但这里可能并非如此。也许这只是模棱两可?
在我看来,这似乎是获得概念模板参数需要回答的主要问题。
另一个问题可能是,我可以写吗foo<convertible_to<int>>(42)
?convertible_to<int>
并不是一个真正的一元概念,但它是一种类型约束,在某些情况下被视为一个,所以我仍然希望它能够工作。
一旦我们有了这样的东西,我相信 Boost.Mp11 会很快获得类似的东西:
template <template <typename...> concept C>
struct mp_quote_c {
template <typename... T>
using fn = mp_bool<C<T...>>;
};
这样你就可以写:
constexpr int count = mp_count_if_q<my_types, mp_quote_c<std::floating_point>>::value;
推荐阅读
- ios - 中时间格式为 24 小时制
- javascript - 由于 iOS 12.4 iframe 无法更改顶部 url
- javascript - 试图从(“\uf2bb”-字体真棒图标)中删除\u。这样我就可以得到“f2bb”
- javascript - 将显示/隐藏和按钮切换到新页面以在 php 中显示某些记录字段
- javascript - 如何简单地将静态/常量值分组到一个“命名空间”中
- javascript - 删除画布对象 mouseclick 事件
- c# - 设计问题 - 使用 C# 代码更改我的 SSIS 包中的 SQL 查询
- python - 如何通过“排除”条件创建行并扩展到现有数据框?
- google-chrome-devtools - 源面板中脚本行旁边显示的这些时间是什么?
- python - Python:为所有测试方法模拟一次补丁类?