使用std::is_invocable无法检测模板成员函数serialise_deserialise的问题
问题
尝试用std::is_invocable检测模板参数类型是否存在名为serialise_deserialise()的成员函数,初始代码报错:'MySerializableType::serialise_deserialise': incorrect argument to 'decltype'。修改检测语句为std::is_invocable_v<decltype(&U::template serialise_deserialise<serialiser_deserialiser>), serialiser_deserialiser>后,static_assert仍失败,即使改用int作为参数也无法解决,为何无法识别U存在serialise_deserialise函数?
代码示例:
template <bool bIsInSerialiseMode> struct serialiser_deserialiser { template <typename U> void read_or_write(U& obj_to_write) { constexpr bool bDoesTypeHaveSerialiseDeserialiseFunction = std::is_invocable_v<decltype(&U::serialise_deserialise), serialiser_deserialiser>; //static_assert (bDoesTypeHaveSerialiseDeserialiseFunction); if constexpr (bDoesTypeHaveSerialiseDeserialiseFunction) /* SOMETHING*/; else ; } }; struct MySerializableType { template <typename serialiser_t> void serialise_deserialise(serialiser_t& serialiser_deserialiser) { // MY TYPE HAS THIS FUNCTION SO I WAS HOPING IT WOULD BE RECOGNIZED } }; int main() { serialiser_deserialiser<true> serialiser_obj; MySerializableType serializable_type; serialiser_obj.read_or_write(serializable_type); }
原因分析
- 模板成员函数的地址无法直接推导:
U::serialise_deserialise是模板成员函数,编译器无法从&U::serialise_deserialise直接确定具体的实例化版本,必须显式指定模板参数才能获得有效的函数指针。 - 成员函数调用的参数缺失:成员函数指针的调用需要两个核心要素:对象实例(
U&)和函数参数(serialiser_deserialiser&)。修改后的std::is_invocable_v只传入了函数参数类型,缺少调用成员函数必须的U对象实例,导致检测逻辑不成立。
修复方案
方案1:修正std::is_invocable的参数
显式指定模板成员函数的实例,并补充调用所需的对象参数:
constexpr bool bDoesTypeHaveSerialiseDeserialiseFunction = std::is_invocable_v<decltype(&U::template serialise_deserialise<serialiser_deserialiser>), U&, serialiser_deserialiser&>;
这里的U&是调用成员函数的对象实例,serialiser_deserialiser&是函数的参数类型,完全符合成员函数指针的调用规则。
方案2:使用C++20 requires表达式(更直观)
C++20的requires表达式可以直接检测表达式是否合法,无需处理成员函数指针的复杂语法:
constexpr bool bDoesTypeHaveSerialiseDeserialiseFunction = requires(U& obj, serialiser_deserialiser& ser) { obj.serialise_deserialise(ser); };
这种方式直接模拟了函数调用的场景,编译器会自动推导模板成员函数的参数,代码可读性更强。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

