考虑 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
,为什么概念上似乎不能发生同样的情况?
最佳答案
字面上的答案是,我们有模板模板参数,但没有概念模板参数,因此您不能将概念作为模板参数传递。
另一个字面上的答案是,它从来不是原始概念提案的一部分,也没有人努力将其建议为扩展(尽管我一直 collecting use-cases )。
必须回答的一件事是依赖概念如何影响包含 - 因为当前概念的使用从来都不是依赖的,所以弄清楚包含是很简单的(实际上,它仍然一点也不简单,但至少你所知道的所有事情)需要就在那里)。但在这样的场景中:
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;
关于c++ - 为什么概念不能传递给模板元函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68588461/