为何使用declval时C++ requires子句无法返回true?
C++ requires子句结合declval使用失效的问题
问题重现
尝试用C++的requires子句判断类型是否包含特定静态成员时,传入实际对象的函数能正常生效,但用declval生成对象的函数却失败,代码如下:
struct ImageMipInfo { ImageMipInfo() {} ImageMipInfo(int a) {} static inline constexpr int JUST_SERIALISE_ME_BY_MEMCPYING{}; }; template <typename T> static constexpr bool isTypeMemcopyableUsingArgumentObject(T& arg) { constexpr bool bHasMemcpyOverride = requires { arg.JUST_SERIALISE_ME_BY_MEMCPYING; }; return bHasMemcpyOverride; } template <typename T> static constexpr bool isTypeMemcopyableUsingDeclVal() { constexpr bool bHasMemcpyOverride = requires { declval<T>().JUST_SERIALISE_ME_BY_MEMCPYING; }; return bHasMemcpyOverride; } int main() { ImageMipInfo mip_info; static_assert(isTypeMemcopyableUsingArgumentObject(mip_info)); // 正常通过 static_assert(isTypeMemcopyableUsingDeclVal<ImageMipInfo>()); // 断言失败 }
编译器错误信息
- Clang:
error: static assertion failed due to requirement
- GCC:
error: there are no arguments to 'declval' that depend on a template parameter, so a declaration of 'declval' must be available
问题原因
declval使用不规范:declval是C++标准库工具,位于<utility>头文件的std命名空间中,代码既未包含对应头文件,也未添加std::限定,导致编译器无法识别该函数。- 静态成员访问冗余:
JUST_SERIALISE_ME_BY_MEMCPYING是类的静态成员,访问静态成员不需要通过对象实例,用declval<T>()生成对象访问完全多余,反而引入编译问题。
修复方案
方案1:修正declval的使用(不推荐,冗余)
添加<utility>头文件,并给declval加上std::限定:
#include <utility> // 必须包含的头文件 template <typename T> static constexpr bool isTypeMemcopyableUsingDeclVal() { constexpr bool bHasMemcpyOverride = requires { std::declval<T>().JUST_SERIALISE_ME_BY_MEMCPYING; }; return bHasMemcpyOverride; }
方案2:直接通过类型访问静态成员(推荐)
既然是静态成员,直接用T::访问,完全不需要declval:
template <typename T> static constexpr bool isTypeMemcopyableUsingDeclVal() { constexpr bool bHasMemcpyOverride = requires { T::JUST_SERIALISE_ME_BY_MEMCPYING; }; return bHasMemcpyOverride; }
修复后,两个static_assert均能正常通过编译。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

