c++ (How)我可以在一个地方推断模板类型参数,而在其他地方“只使用”推断的类型吗?

gg58donl  于 2023-04-08  发布在  其他
关注(0)|答案(2)|浏览(124)

我的函数模板有一个函数指针(或成员函数指针)参数。函数指针可以接受任何参数,参数类型将被推断。在参数列表的末尾,我希望函数模板接受与函数指针参数相同的参数。

template<typename R, typename... Args>
void f(R(*fp)(Args...), Args... args);

当参数类型不完全匹配时,问题就开始了,例如,假设fp接受Base*,而f的调用者给了你一个Derived*,或者fp接受double,而调用者放入0(类型为int)。
有没有什么方法可以告诉编译器只根据fp推断Args,并且“只使用”args的推断类型,而不尝试根据它们绑定的参数来匹配它们?

jjhzyzn0

jjhzyzn01#

我找到了一个有效的解决方案。我不知道的术语是非推导上下文。例如,范围解析运算符::左边的所有内容都是非推导的。在C20中,您可以使用std::type_identity_t人工创建这样的上下文,在C14和C ++17中,您可以创建自己的type_identity_t
所以你会用

template<typename R, typename... Args>
void f(R(*fp)(Args...), std::type_identity_t<Args>... args);

关于完美转发,当fp通过引用或值接受参数时,f也会这样做。对于std::forward,一个通过值的参数将被移动,一个引用参数将被引用。

vaj7vani

vaj7vani2#

一种选择是为both1推导不同的类型,并使用SFINAE或概念在以下情况下禁用重载:

// no SFINAE
template <typename R, typename... Args, typename... UArgs>
void f(R (*fp)(Args...), UArgs&&... args);

// SFINAE
template <typename R, typename... Args, typename... UArgs>
auto f(R (*fp)(Args...), UArgs&&... args)
    -> std::void_t<std::invoke_result_t<decltype(fp), UArgs...>>;

// concepts
template <typename R, typename... Args, typename... UArgs>
auto f(R (*fp)(Args...), UArgs&&... args)
    requires std::invocable<decltype(fp), UArgs...>;

此选项与std::type_identity one的一个区别是,当您使用需要转换为fp的参数调用f时,例如。

struct X { X(int); };
void f1(X);

f(&f1, 33); // implicit conversion from int to X

std::type_identity的情况下,转换是在调用方完成的(即,当您调用f时),而使用上面的选项时,转换是在您调用f内部的fp时完成的。
1你也可以使用一个泛型函数类型,就像注解中建议的那样,这取决于你在f()中做了什么。

相关问题