C++ 概念 - 要求括号中的概念导致 2 条相互冲突的错误消息
C++ Concepts - Concept in the requires parenthesis causes 2 conflicting error messages
今天早上我努力工作以更多地理解概念(仍然是新手),但我偶然发现了一些东西 st运行ge.
我想了解好的概念如何与 Lambda 函数一起使用,我已经尝试了很多次。
让我们从这段代码开始(有效!):
#include <concepts>
#include <stdio.h>
template <typename T>
concept Integral =
requires(T n)
{
{ n } -> std::convertible_to<int>;
};
template <typename Operation>
concept CalculatorOperation =
requires(Operation&& op, int a, int b)
{
{ op(a, b) } -> Integral;
};
template <CalculatorOperation Operation>
static inline constexpr Integral auto Calculator(const Integral auto First,
const Integral auto Second)
{
return Operation{}(First, Second);
}
int main()
{
static constexpr auto Multiply = [](const Integral auto First,
const Integral auto Second)
{ return First * Second; };
return Calculator<decltype(Multiply)>(15, 18);
}
我创建了一个积分概念,如果类型可转换为 int,则满足该概念(只是为了模拟)。
我创建了一个计算器操作概念,它接受一个 lambda、两个整数,并确保操作 returns 是一个整数。
我决定要把概念里的int变成一个Integral ,因为我不想只接受 int 的操作(我想要所有整数类型)。
所以我改变了
requires(Operation&& op, int a, int b)
到
requires(Operation&& op, Integral&& a, Integral&& b)
这不仅对我不起作用,我还收到了 2 条相互矛盾的错误消息(在 GCC 10.1 上):
<source>:13:30: error: placeholder type not allowed in this context
<source>:13:30: error: expected 'auto' or 'decltype(auto)' after 'Integral'
13 | requires(Operation&& op, Integral&& a, Integral&& b)
我 运行 使用 GodBolt 的网站 Compiler Explorer。
这里发生了什么?有没有实际的方法可以做到这一点?
首先,通过这样做:
requires(Operation&& op, Integral&& a, Integral&& b)
你可能真的是这个意思:
requires(Operation op, Integral auto a, Integral auto b)
也就是说,使用 type-constraint auto
形式的占位符类型说明符。
然而,auto
参数产生函数模板,auto
占位符等同于该函数模板的实际发明类型模板参数,因此它只能出现在类型推导的上下文中来自初始化程序的发生,这意味着:
void foo(auto x);
相当于:
template <typename T>
void foo(T x);
同样,
void bar(Integral auto x);
相当于:
template <Integral T>
void bar(T x);
这种转换不适用于 requires 表达式,即没有可以推导出类型的初始化器,因此不能在需求参数列表的参数声明中使用 auto
占位符。这些参数,正如标准所说,"are only used as notation for the purpose of defining requirements." 因此,您需要明确指定概念工作所需的所有模板参数,例如:
template <typename Operation, typename Lhs, typename Rhs>
concept CalculatorOperation = requires(Operation op, Lhs a, Rhs b)
{
{ op(a, b) } -> Integral;
};
template <typename Operation>
constexpr Integral auto Calculator(Integral auto first, Integral auto second)
requires CalculatorOperation<Operation, decltype(first), decltype(second)>
{
return Operation{}(first, second);
}
另请注意,我从需求参数列表中的每个参数声明中删除了 &&
。整个 requires 表达式是一个未计算的上下文,实际上没有传递 arguments。
今天早上我努力工作以更多地理解概念(仍然是新手),但我偶然发现了一些东西 st运行ge.
我想了解好的概念如何与 Lambda 函数一起使用,我已经尝试了很多次。
让我们从这段代码开始(有效!):
#include <concepts>
#include <stdio.h>
template <typename T>
concept Integral =
requires(T n)
{
{ n } -> std::convertible_to<int>;
};
template <typename Operation>
concept CalculatorOperation =
requires(Operation&& op, int a, int b)
{
{ op(a, b) } -> Integral;
};
template <CalculatorOperation Operation>
static inline constexpr Integral auto Calculator(const Integral auto First,
const Integral auto Second)
{
return Operation{}(First, Second);
}
int main()
{
static constexpr auto Multiply = [](const Integral auto First,
const Integral auto Second)
{ return First * Second; };
return Calculator<decltype(Multiply)>(15, 18);
}
我创建了一个积分概念,如果类型可转换为 int,则满足该概念(只是为了模拟)。 我创建了一个计算器操作概念,它接受一个 lambda、两个整数,并确保操作 returns 是一个整数。
我决定要把概念里的int变成一个Integral ,因为我不想只接受 int 的操作(我想要所有整数类型)。
所以我改变了
requires(Operation&& op, int a, int b)
到
requires(Operation&& op, Integral&& a, Integral&& b)
这不仅对我不起作用,我还收到了 2 条相互矛盾的错误消息(在 GCC 10.1 上):
<source>:13:30: error: placeholder type not allowed in this context
<source>:13:30: error: expected 'auto' or 'decltype(auto)' after 'Integral'
13 | requires(Operation&& op, Integral&& a, Integral&& b)
我 运行 使用 GodBolt 的网站 Compiler Explorer。 这里发生了什么?有没有实际的方法可以做到这一点?
首先,通过这样做:
requires(Operation&& op, Integral&& a, Integral&& b)
你可能真的是这个意思:
requires(Operation op, Integral auto a, Integral auto b)
也就是说,使用 type-constraint auto
形式的占位符类型说明符。
然而,auto
参数产生函数模板,auto
占位符等同于该函数模板的实际发明类型模板参数,因此它只能出现在类型推导的上下文中来自初始化程序的发生,这意味着:
void foo(auto x);
相当于:
template <typename T>
void foo(T x);
同样,
void bar(Integral auto x);
相当于:
template <Integral T>
void bar(T x);
这种转换不适用于 requires 表达式,即没有可以推导出类型的初始化器,因此不能在需求参数列表的参数声明中使用 auto
占位符。这些参数,正如标准所说,"are only used as notation for the purpose of defining requirements." 因此,您需要明确指定概念工作所需的所有模板参数,例如:
template <typename Operation, typename Lhs, typename Rhs>
concept CalculatorOperation = requires(Operation op, Lhs a, Rhs b)
{
{ op(a, b) } -> Integral;
};
template <typename Operation>
constexpr Integral auto Calculator(Integral auto first, Integral auto second)
requires CalculatorOperation<Operation, decltype(first), decltype(second)>
{
return Operation{}(first, second);
}
另请注意,我从需求参数列表中的每个参数声明中删除了 &&
。整个 requires 表达式是一个未计算的上下文,实际上没有传递 arguments。