You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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版本的赋值运算符不存在,导致断言失败。

验证与解决

可以通过两种方式验证并解决该问题:

  1. 显式指定变量类型,避免自动推导带来的const属性混淆:
    inline constexpr func_getter<X, int> a_getter = func_getter(&X::GetA);
    
  2. 将constexpr替换为const,此时MSVC能正确识别类型的const属性:
    inline const auto a_getter = func_getter(&X::GetA);
    

修改后,MSVC的赋值断言会正常通过,且符合C++标准的预期。

内容的提问来源于stack exchange,提问作者Alexey Starinsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 03:11:24