这是一个带有 C++20 概念的 gcc 11 编译器错误,还是我做错了什么?
Is this a gcc 11 compiler bug with C++20 concepts, or am I doing something wrong?
我正在试验 C++20 概念,使用我自己本地构建的 GCC 11 源代码的克隆。我从 GCC 收到编译错误,这对我来说似乎是错误的。我已将触发诊断的代码减少到以下内容,使用 GCC 命令行对其进行编译,并在其下方生成完整的诊断输出。
为了重点,诊断输出中对我来说似乎错误的特定部分是
repro.cpp:9:13: note: the required expression ‘flequal(a, b)’ is invalid, because
9 | {flequal(a, b)} -> std::convertible_to<bool>;
| ~~~~~~~^~~~~~
repro.cpp:9:13: error: ‘flequal’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
repro.cpp:22:6: note: ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&)’ declared here, later in the translation unit
22 | bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
| ^~~~~~~
它说候选函数在翻译单元中的声明晚于实例化点,但事实并非如此,至少按照我的代码片段中的源代码行顺序是这样。
这个构建错误是错误的,还是我在使用 C++20 概念时做错了什么?
注意代码末尾的注释中的变体,它编译时没有任何诊断。
代码:
#include <concepts>
using std::floating_point;
template< typename T >
concept Flequalable
= floating_point<T>
&& requires(T a, T b) {
{flequal(a, b)} -> std::convertible_to<bool>;
};
template<floating_point T>
bool flequal( T a, T b) {
return true;
}
template<typename T>
struct Bar {
T t;
};
bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
return true;
}
bool foo() {
Bar<double> a = {2.0};
Bar<double> b = {3.0};
return flequal(a, b); // Causes diagnostic
// return flequal(a.t, b.t); // This works
}
编译命令行:
/usr/local/gcc-11-master/bin/g++-11 -c repro.cpp -o repro.o -std=c++20 -fconcepts-diagnostics-depth=5 2> diagnostic.txt
完整的 GCC 诊断:
repro.cpp: In function ‘bool foo()’:
repro.cpp:29:24: error: no matching function for call to ‘flequal(Bar<double>&, Bar<double>&)’
29 | return flequal(a, b); // Causes diagnostic
| ^
repro.cpp:13:6: note: candidate: ‘template<class T> requires floating_point<T> bool flequal(T, T)’
13 | bool flequal( T a, T b) {
| ^~~~~~~
repro.cpp:13:6: note: template argument deduction/substitution failed:
repro.cpp:13:6: note: constraints not satisfied
In file included from repro.cpp:1:
/usr/local/gcc-11-master/include/c++/11.0.1/concepts: In substitution of ‘template<class T> requires floating_point<T> bool flequal(T, T) [with T = Bar<double>]’:
repro.cpp:29:24: required from here
/usr/local/gcc-11-master/include/c++/11.0.1/concepts:111:13: required for the satisfaction of ‘floating_point<T>’ [with T = Bar<double>]
/usr/local/gcc-11-master/include/c++/11.0.1/concepts:111:30: note: the expression ‘is_floating_point_v<_Tp> [with _Tp = Bar<double>]’ evaluated to ‘false’
111 | concept floating_point = is_floating_point_v<_Tp>;
| ^~~~~~~~~~~~~~~~~~~~~~~~
repro.cpp:22:6: note: candidate: ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&)’
22 | bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
| ^~~~~~~
repro.cpp:22:6: note: template argument deduction/substitution failed:
repro.cpp:22:6: note: constraints not satisfied
repro.cpp: In substitution of ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&) [with auto:1 = double; auto:2 = double]’:
repro.cpp:29:24: required from here
repro.cpp:6:9: required for the satisfaction of ‘Flequalable<auto:1>’ [with auto:1 = double]
repro.cpp:8:8: in requirements with ‘T a’, ‘T b’ [with T = double]
repro.cpp:9:13: note: the required expression ‘flequal(a, b)’ is invalid, because
9 | {flequal(a, b)} -> std::convertible_to<bool>;
| ~~~~~~~^~~~~~
repro.cpp:9:13: error: ‘flequal’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
repro.cpp:22:6: note: ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&)’ declared here, later in the translation unit
22 | bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
| ^~~~~~~
这里是准确的 GCC 版本信息:
Using built-in specs.
COLLECT_GCC=/usr/local/gcc-11-master/bin/g++-11
COLLECT_LTO_WRAPPER=/usr/local/gcc-11-master/libexec/gcc/x86_64-pc-linux-gnu/11.0.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc/configure --prefix=/usr/local/gcc-11-master --program-suffix=-11 --enable-libstdcxx-debug : (reconfigured) ../gcc/configure --prefix=/usr/local/gcc-11-master --program-suffix=-11 --enable-libstdcxx-debug
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 11.0.1 20210304 (experimental) (GCC)
首先,Bar<Flequalable auto>
不是有效语法。您可以像 Concept auto v
这样声明一个顶级变量,但不能将其嵌套在模板中。所以它真的应该是:
template <Flequalable T, Flequalable U>
bool flequal(Bar<T> const &a, Bar<U> const &b) {
return true;
}
现在,当我们尝试调用 flequal(a, b)
时会发生什么。我们推导出 T=double
和 U=double
,然后尝试评估 double
是否满足 Flequalable
。 double
是 floating_point
,所以我们继续检查 flequal(a, b)
是两个 double
的有效表达式的要求。
这是非限定查找,所以我们首先对名称flequal
进行常规非限定查找。请务必记住,此查找是从 概念定义 的角度进行的,而不是从使用它的角度进行的。也就是说,我们从这里向上看:
#include <concepts>
using std::floating_point;
template< typename T >
concept Flequalable
= floating_point<T>
&& requires(T a, T b) {
{flequal(a, b)} -> std::convertible_to<bool>; // <== here!
};
不是使用概念的地方:
template <Flequalable T, Flequalable U> // <== not here
bool flequal(Bar<T> const &a, Bar<U> const &b) {
return true;
}
也没有调用使用概念的函数模板的地方:
return flequal(a, b); // <== not here either
我们什么也没找到。从那时起没有可见的 flequal
声明。然后,我们进行参数相关查找。 double
没有 关联的命名空间,所以这个 also 也找不到任何东西。因此,候选者为零,因此 double
不满足 Flequalable
.
为了完成这项工作,您必须确保概念 Flequalable
中的非限定查找实际上找到了您的 flequal
函数。只需交换两个声明,然后一切正常。
这使得 flequal
看起来像是某种自定义点,但只有固定数量的 floating_point
类型(float
、double
、long double
,及其 cv 限定版本)所以我不完全确定这里的重点是什么。
我正在试验 C++20 概念,使用我自己本地构建的 GCC 11 源代码的克隆。我从 GCC 收到编译错误,这对我来说似乎是错误的。我已将触发诊断的代码减少到以下内容,使用 GCC 命令行对其进行编译,并在其下方生成完整的诊断输出。
为了重点,诊断输出中对我来说似乎错误的特定部分是
repro.cpp:9:13: note: the required expression ‘flequal(a, b)’ is invalid, because
9 | {flequal(a, b)} -> std::convertible_to<bool>;
| ~~~~~~~^~~~~~
repro.cpp:9:13: error: ‘flequal’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
repro.cpp:22:6: note: ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&)’ declared here, later in the translation unit
22 | bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
| ^~~~~~~
它说候选函数在翻译单元中的声明晚于实例化点,但事实并非如此,至少按照我的代码片段中的源代码行顺序是这样。
这个构建错误是错误的,还是我在使用 C++20 概念时做错了什么?
注意代码末尾的注释中的变体,它编译时没有任何诊断。
代码:
#include <concepts>
using std::floating_point;
template< typename T >
concept Flequalable
= floating_point<T>
&& requires(T a, T b) {
{flequal(a, b)} -> std::convertible_to<bool>;
};
template<floating_point T>
bool flequal( T a, T b) {
return true;
}
template<typename T>
struct Bar {
T t;
};
bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
return true;
}
bool foo() {
Bar<double> a = {2.0};
Bar<double> b = {3.0};
return flequal(a, b); // Causes diagnostic
// return flequal(a.t, b.t); // This works
}
编译命令行:
/usr/local/gcc-11-master/bin/g++-11 -c repro.cpp -o repro.o -std=c++20 -fconcepts-diagnostics-depth=5 2> diagnostic.txt
完整的 GCC 诊断:
repro.cpp: In function ‘bool foo()’:
repro.cpp:29:24: error: no matching function for call to ‘flequal(Bar<double>&, Bar<double>&)’
29 | return flequal(a, b); // Causes diagnostic
| ^
repro.cpp:13:6: note: candidate: ‘template<class T> requires floating_point<T> bool flequal(T, T)’
13 | bool flequal( T a, T b) {
| ^~~~~~~
repro.cpp:13:6: note: template argument deduction/substitution failed:
repro.cpp:13:6: note: constraints not satisfied
In file included from repro.cpp:1:
/usr/local/gcc-11-master/include/c++/11.0.1/concepts: In substitution of ‘template<class T> requires floating_point<T> bool flequal(T, T) [with T = Bar<double>]’:
repro.cpp:29:24: required from here
/usr/local/gcc-11-master/include/c++/11.0.1/concepts:111:13: required for the satisfaction of ‘floating_point<T>’ [with T = Bar<double>]
/usr/local/gcc-11-master/include/c++/11.0.1/concepts:111:30: note: the expression ‘is_floating_point_v<_Tp> [with _Tp = Bar<double>]’ evaluated to ‘false’
111 | concept floating_point = is_floating_point_v<_Tp>;
| ^~~~~~~~~~~~~~~~~~~~~~~~
repro.cpp:22:6: note: candidate: ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&)’
22 | bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
| ^~~~~~~
repro.cpp:22:6: note: template argument deduction/substitution failed:
repro.cpp:22:6: note: constraints not satisfied
repro.cpp: In substitution of ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&) [with auto:1 = double; auto:2 = double]’:
repro.cpp:29:24: required from here
repro.cpp:6:9: required for the satisfaction of ‘Flequalable<auto:1>’ [with auto:1 = double]
repro.cpp:8:8: in requirements with ‘T a’, ‘T b’ [with T = double]
repro.cpp:9:13: note: the required expression ‘flequal(a, b)’ is invalid, because
9 | {flequal(a, b)} -> std::convertible_to<bool>;
| ~~~~~~~^~~~~~
repro.cpp:9:13: error: ‘flequal’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
repro.cpp:22:6: note: ‘template<class auto:1, class auto:2> requires (Flequalable<auto:1>) && (Flequalable<auto:2>) bool flequal(const Bar<auto:1>&, const Bar<auto:2>&)’ declared here, later in the translation unit
22 | bool flequal(Bar<Flequalable auto> const &a, Bar<Flequalable auto> const &b) {
| ^~~~~~~
这里是准确的 GCC 版本信息:
Using built-in specs.
COLLECT_GCC=/usr/local/gcc-11-master/bin/g++-11
COLLECT_LTO_WRAPPER=/usr/local/gcc-11-master/libexec/gcc/x86_64-pc-linux-gnu/11.0.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc/configure --prefix=/usr/local/gcc-11-master --program-suffix=-11 --enable-libstdcxx-debug : (reconfigured) ../gcc/configure --prefix=/usr/local/gcc-11-master --program-suffix=-11 --enable-libstdcxx-debug
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 11.0.1 20210304 (experimental) (GCC)
首先,Bar<Flequalable auto>
不是有效语法。您可以像 Concept auto v
这样声明一个顶级变量,但不能将其嵌套在模板中。所以它真的应该是:
template <Flequalable T, Flequalable U>
bool flequal(Bar<T> const &a, Bar<U> const &b) {
return true;
}
现在,当我们尝试调用 flequal(a, b)
时会发生什么。我们推导出 T=double
和 U=double
,然后尝试评估 double
是否满足 Flequalable
。 double
是 floating_point
,所以我们继续检查 flequal(a, b)
是两个 double
的有效表达式的要求。
这是非限定查找,所以我们首先对名称flequal
进行常规非限定查找。请务必记住,此查找是从 概念定义 的角度进行的,而不是从使用它的角度进行的。也就是说,我们从这里向上看:
#include <concepts>
using std::floating_point;
template< typename T >
concept Flequalable
= floating_point<T>
&& requires(T a, T b) {
{flequal(a, b)} -> std::convertible_to<bool>; // <== here!
};
不是使用概念的地方:
template <Flequalable T, Flequalable U> // <== not here
bool flequal(Bar<T> const &a, Bar<U> const &b) {
return true;
}
也没有调用使用概念的函数模板的地方:
return flequal(a, b); // <== not here either
我们什么也没找到。从那时起没有可见的 flequal
声明。然后,我们进行参数相关查找。 double
没有 关联的命名空间,所以这个 also 也找不到任何东西。因此,候选者为零,因此 double
不满足 Flequalable
.
为了完成这项工作,您必须确保概念 Flequalable
中的非限定查找实际上找到了您的 flequal
函数。只需交换两个声明,然后一切正常。
这使得 flequal
看起来像是某种自定义点,但只有固定数量的 floating_point
类型(float
、double
、long double
,及其 cv 限定版本)所以我不完全确定这里的重点是什么。