当首个参数为成员函数指针左值引用时,std::invoke是否应正常工作?
关于std::invoke实现与C++标准解读的疑问
在实现类似std::invoke的功能时,我发现了C标准中的一处细节,需要专业的标准解读来判断libc的实现是否正确。
标准定义引用
C++20对应标准文档N4868中,[func.invoke]对std::invoke的定义如下:
template<class F, class... Args> constexpr invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) noexcept(is_nothrow_invocable_v<F, Args...>);返回值:
INVOKE(std::forward<F>(f), std::forward<Args>(args)...)。
而[func.require]/1对INVOKE的定义如下:
定义
INVOKE(f, t_1, t_2, ..., t_N)的行为如下:
- [...] 当
f是类T的成员函数指针且 [...]- [...] 当
f是类T的成员函数指针且 [...]- [...] 当
f是类T的成员函数指针且 [...]- [...] 当
N == 1且f是类T的数据成员指针且 [...]- [...] 当
N == 1且f是类T的数据成员指针且 [...]- 其他所有情况执行
f(t_1, t_2, ..., t_N)。
测试代码与行为差异
以下代码片段的预期行为存在疑问:
struct Callable { int DoSomething() { return 17; } }; int (Callable::*member_fn_ptr)() = &Callable::DoSomething; assert(17 == std::invoke(member_fn_ptr, Callable{}));
这段代码在libc++中可正常运行,但我的实现会触发编译错误——原因是我的实现会进入“其他所有情况”分支,尝试将成员函数指针当作普通函数指针调用。
核心疑惑
我原本以为是自身实现问题,但研读标准后产生疑惑:std::invoke对参数f使用转发引用并要求转发,该场景下f会被转发为左值引用,此时f并非成员函数指针,而是其左值引用。libc++的<type_traits>实现也验证了这一点:
static_assert(!std::is_member_function_pointer_v<decltype(member_fn_ptr)&>)
而libc++能正常运行,是因为其INVOKE第一个分支的SFINAE检查的是std::decay_t<decltype(f)>是否为成员函数指针,而非decltype(f)。
请问这是libc++的实现缺陷、标准的漏洞,还是我对标准的理解有误?
内容的提问来源于stack exchange,提问作者jacobsa
相关产品推荐
相关产品推荐

