问题描述
如何编写一个 C++ 20 概念,它需要一个成员函数模板,该模板需要一个必须提供的模板参数?
以下概念的目标是检查类型是否类似于元组,除了检查 std::get<I>(t)
我想检查 t.get<I>()
。
以下内容不能使用开关 -std=c++2a
在 g++ 10.1 中编译。
#include <concepts>
template <typename E>
concept Tpl = requires(E const e,int idx)
{
{
e.template get<idx>()
} -> std::convertible_to<float>;
};
如果在 template
之前没有使用 get
,它当然不会编译(没有尖括号,小于/大于运算符)。
解决方法
这个:
template <typename E>
concept Tpl = requires(E const e,int idx)
{
{
e.template get<idx>()
} -> std::convertible_to<float>;
};
不起作用,因为 idx
不是常量表达式,您需要在调用 get
的上下文中将其设为常量表达式。
为此,您需要选择索引的特定值以进行检查。您唯一可以选择的是0
:
template <typename E>
concept Tpl = requires (E const e) {
{ e.template get<0>() } -> std::convertible_to<float>;
};
这可能会匹配具有 get
或 int*
类型的模板参数的函数模板 nullptr_t
。如果这是一个问题,我们可以用更复杂的方式拼写 0
以避免它成为空指针常量,无论是简单的 1-1
还是将 {{1} 类型的对象作为第二个“参数” }}:
integral_constant<size_t,0>
如果最终的目标是检查 template <typename E>
concept Tpl = requires (E const e,std::integral_constant<size_t,0> value) {
{ e.template get<value()>() } -> std::convertible_to<float>;
};
是否适用于 all e.get<I>()
来自 I
,那么您必须以不同的方式处理此问题.在这种情况下,您会希望您正在检查的索引成为概念本身的一部分。如:
[0,tuple_size_v<E>)
然后建立一个 template <typename E,size_t I>
concept tuple_like_impl = requires (E const e) {
{ e.template get<I>() } -> std::convertible_to<float>;
};
的参数包,这样你最终会构造一个像 Is...
这样的约束。
但这是只有在您确实需要时才应该采取的步骤。
,要让它编译,你可以这样写:
template <typename E,int idx>
concept Tpl = requires(E const e)
{
{
e.template get<idx>()
} -> std::convertible_to<float>;
};
但是告诉我们你真正想要什么。