为什么 std::integral_constant<lambda> 的工作方式与 std::integral_constant<function-ptr> 不同?
Why doesn't std::integral_constant<lambda> work the same way as std::integral_constant<function-ptr>?
(与 相关)。
我正在尝试通过 std::integral_constant
组合 unique_ptr
和 lambda(获取大多数标准函数的地址在 C++20 中是非法的,我正在寻找一种将它们包装在 lambda 中的便捷方法).我注意到 std::integral_constant
的奇怪行为,我无法解释 (godbolt):
#include <type_traits>
template<auto L, class T = decltype(L)>
using constant = std::integral_constant<T, L>;
void dummy(void*);
int main()
{
using C1 = constant<&dummy>;
using C2 = constant<[](void* p){ dummy(p); }>;
C1()()(nullptr); // #1 works as expected
C2()()(nullptr); // #2 works as expected
C1()(nullptr); // #3 unexpectedly works
C2()(nullptr); // #4 fails as expected
return 0;
}
有人可以解释为什么第 3 行可以编译吗?这就是 std::unique_ptr
隐藏的用途(当您使用 std::integral_constant
作为删除器时),这就是为什么我尝试使用 lambda 而不是函数地址失败的原因。
P.S。第 4 行失败并显示以下消息:
<source>: In function 'int main()':
<source>:17:17: error: no match for call to '(C2 {aka std::integral_constant<const main()::<lambda(void*)>, <lambda closure object>main()::<lambda(void*)>{}>}) (std::nullptr_t)'
17 | C2()(nullptr); // #4 fails as expected
在对象上执行函数调用时,不仅要考虑调用运算符。如果存在 non-explicit 到具有合适 cvref-qualifiers 的函数指针类型(或函数引用类型)的转换函数,则有一个特殊的例外。
在这些情况下 [over.call.object]/2 表示生成了一个额外的重载,一个 代理调用函数 将转换后的隐式对象指针作为第一个参数,函数 pointer/reference的参数作为进一步的参数。如果选择此重载,它将使用转换函数将 this
转换为函数 pointer/reference,然后使用剩余提供的参数调用它。
std::integral_constant
有一个 non-explicit 到 value_type
的转换函数,所以如果 value_type
是一个函数 pointer/reference,只有这样,这个代理才会调用存在,它实质上将对象函数调用转发到对存储函数的调用 pointer/reference.
(与
我正在尝试通过 std::integral_constant
组合 unique_ptr
和 lambda(获取大多数标准函数的地址在 C++20 中是非法的,我正在寻找一种将它们包装在 lambda 中的便捷方法).我注意到 std::integral_constant
的奇怪行为,我无法解释 (godbolt):
#include <type_traits>
template<auto L, class T = decltype(L)>
using constant = std::integral_constant<T, L>;
void dummy(void*);
int main()
{
using C1 = constant<&dummy>;
using C2 = constant<[](void* p){ dummy(p); }>;
C1()()(nullptr); // #1 works as expected
C2()()(nullptr); // #2 works as expected
C1()(nullptr); // #3 unexpectedly works
C2()(nullptr); // #4 fails as expected
return 0;
}
有人可以解释为什么第 3 行可以编译吗?这就是 std::unique_ptr
隐藏的用途(当您使用 std::integral_constant
作为删除器时),这就是为什么我尝试使用 lambda 而不是函数地址失败的原因。
P.S。第 4 行失败并显示以下消息:
<source>: In function 'int main()':
<source>:17:17: error: no match for call to '(C2 {aka std::integral_constant<const main()::<lambda(void*)>, <lambda closure object>main()::<lambda(void*)>{}>}) (std::nullptr_t)'
17 | C2()(nullptr); // #4 fails as expected
在对象上执行函数调用时,不仅要考虑调用运算符。如果存在 non-explicit 到具有合适 cvref-qualifiers 的函数指针类型(或函数引用类型)的转换函数,则有一个特殊的例外。
在这些情况下 [over.call.object]/2 表示生成了一个额外的重载,一个 代理调用函数 将转换后的隐式对象指针作为第一个参数,函数 pointer/reference的参数作为进一步的参数。如果选择此重载,它将使用转换函数将 this
转换为函数 pointer/reference,然后使用剩余提供的参数调用它。
std::integral_constant
有一个 non-explicit 到 value_type
的转换函数,所以如果 value_type
是一个函数 pointer/reference,只有这样,这个代理才会调用存在,它实质上将对象函数调用转发到对存储函数的调用 pointer/reference.