结合范围适配器和 std::source_location 得到奇怪的结果
Combining ranges adaptors and std::source_location got strange results
#include <ranges>
#include <source_location>
#include <iostream>
int main() {
auto lines = std::views::iota(0, 5)
| std::views::transform(
[](int, const std::source_location& location = std::source_location::current())
{ return location.line(); }
);
for (const auto& line : lines)
std::cout << line << "\n";
}
MSVC 拒绝并显示奇怪的错误消息:
(7): error C2676: binary '|': 'std::ranges::iota_view<_Ty1,_Ty2>' does not define this operator or a conversion to a type acceptable to the predefined operator
with
[
_Ty1=int,
_Ty2=int
]
并且 GCC 输出奇怪的行号 61
无论 std::source_location::current()
在哪一行:
61
61
61
61
61
上面的代码格式正确吗?如果是,是不是意味着MSVC和GCC都有bug?
gcc 正确,程序完全有效。
And GCC outputs strange line number 61
no matter which row the std::source_location::current()
is in:
这是因为默认函数参数 current()
是在函数 call 处求值的,这与函数所在位置无关 已声明.
并且这个函数被transform_view
的iterator
的operator*()
调用。但不是直接由 operator*()
,该运算符将调用 invoke
,它本身将不得不做大量工作以确保它被正确调用。被调用的 libstdc++ 实现的 invoke
中的实际最终重载是...哦,看看那个,它是 bits/invoke.h:61
:
template<typename _Res, typename _Fn, typename... _Args>
constexpr _Res
__invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args)
{ return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); }
如果您不只是打印 source_location
给您的行号,还打印了文件 name:[=27,这会更容易发现=]
auto lines = std::views::iota(0, 5)
| std::views::transform(
[](int, const std::source_location& location = std::source_location::current())
{ return fmt::format("{}:{}", location.file_name(), location.line()); }
);
fmt::print("{}\n", lines);
打印包含字符串 /opt/compiler-explorer/gcc-trunk-20210817/include/c++/12.0.0/bits/invoke.h:61
的范围五次。
#include <ranges>
#include <source_location>
#include <iostream>
int main() {
auto lines = std::views::iota(0, 5)
| std::views::transform(
[](int, const std::source_location& location = std::source_location::current())
{ return location.line(); }
);
for (const auto& line : lines)
std::cout << line << "\n";
}
MSVC 拒绝并显示奇怪的错误消息:
(7): error C2676: binary '|': 'std::ranges::iota_view<_Ty1,_Ty2>' does not define this operator or a conversion to a type acceptable to the predefined operator
with
[
_Ty1=int,
_Ty2=int
]
并且 GCC 输出奇怪的行号 61
无论 std::source_location::current()
在哪一行:
61
61
61
61
61
上面的代码格式正确吗?如果是,是不是意味着MSVC和GCC都有bug?
gcc 正确,程序完全有效。
And GCC outputs strange line number
61
no matter which row thestd::source_location::current()
is in:
这是因为默认函数参数 current()
是在函数 call 处求值的,这与函数所在位置无关 已声明.
并且这个函数被transform_view
的iterator
的operator*()
调用。但不是直接由 operator*()
,该运算符将调用 invoke
,它本身将不得不做大量工作以确保它被正确调用。被调用的 libstdc++ 实现的 invoke
中的实际最终重载是...哦,看看那个,它是 bits/invoke.h:61
:
template<typename _Res, typename _Fn, typename... _Args> constexpr _Res __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); }
如果您不只是打印 source_location
给您的行号,还打印了文件 name:[=27,这会更容易发现=]
auto lines = std::views::iota(0, 5)
| std::views::transform(
[](int, const std::source_location& location = std::source_location::current())
{ return fmt::format("{}:{}", location.file_name(), location.line()); }
);
fmt::print("{}\n", lines);
打印包含字符串 /opt/compiler-explorer/gcc-trunk-20210817/include/c++/12.0.0/bits/invoke.h:61
的范围五次。