为何C++中func_getter类对象无法被赋值?
MSVC2022中func_getter类赋值断言失败的原因分析
问题描述
我们定义了如下C++代码,其中成员函数指针类型GetAPtr的std::is_copy_assignable_v、std::is_move_assignable_v等断言均通过;func_getter类的拷贝构造、移动构造断言也通过,但在MSVC2022环境下,该类对象的拷贝赋值、移动赋值断言却失败了,请问原因是什么?
示例代码
#include <type_traits> #include <string> template <class T, class ReturnType> using FuncPtr = ReturnType(T::*)() const; template <class T, class ReturnType> class func_getter { public: using MyFuncPtr = FuncPtr<T, ReturnType>; constexpr func_getter(MyFuncPtr p) : m_p(p) {} func_getter(const func_getter&) = default; func_getter(func_getter&&) = default; func_getter& operator = (const func_getter&) = default; func_getter& operator = (func_getter&&) = default; constexpr ReturnType operator() (const T& val) const { return (val.*m_p)(); } private: MyFuncPtr m_p; }; struct X { int a; std::string b; int GetA() const { return a; } int GetA1() const { return a; } }; using GetAPtr = FuncPtr<X, int>; static_assert(std::is_copy_constructible_v<GetAPtr>); static_assert(std::is_copy_assignable_v<GetAPtr>); static_assert(std::is_move_constructible_v<GetAPtr>); static_assert(std::is_move_assignable_v<GetAPtr>); inline constexpr auto a_getter = func_getter(&X::GetA); static_assert(std::is_copy_constructible_v<decltype(a_getter)>); static_assert(std::is_move_constructible_v<decltype(a_getter)>); // 以下断言在MSVC2022中失败 static_assert(std::is_copy_assignable_v<decltype(a_getter)>); static_assert(std::is_move_assignable_v<decltype(a_getter)>);
原因分析
这是MSVC的编译器bug,核心问题在于constexpr变量的类型推导与赋值运算符的删除规则处理不一致:
constexpr变量默认带有const属性,因此decltype(a_getter)的实际类型是const func_getter<X, int>。- 根据C++标准,
const修饰的类对象,其默认生成的赋值运算符(即使是=default)会被隐式删除——因为不允许修改const对象。 - 但MSVC错误地没有识别出
decltype(a_getter)的const属性,反而错误判定非const版本的赋值运算符不存在,导致断言失败。
验证与解决
可以通过两种方式验证并解决该问题:
- 显式指定变量类型,避免自动推导带来的const属性混淆:
inline constexpr func_getter<X, int> a_getter = func_getter(&X::GetA); - 将
constexpr替换为const,此时MSVC能正确识别类型的const属性:inline const auto a_getter = func_getter(&X::GetA);
修改后,MSVC的赋值断言会正常通过,且符合C++标准的预期。
内容的提问来源于stack exchange,提问作者Alexey Starinsky
相关产品推荐
相关产品推荐

