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

如何通过模板访问结构体数据成员?C++代码异常输出问题排查

问题:修正基于类成员指针的模板类逻辑错误

需求是实现一个模板类,以类的成员指针作为模板参数,传入类实例后能对指定成员执行操作。现有代码输出不符合预期,具体代码与错误输出如下:

原代码

#include <functional>
#include <iostream>

struct B
{
    int foo;
    bool bar;
};

template<auto M>
class A
{
public:
    typedef std::function<bool(decltype(std::declval<B>().*M)&)> Callback;

    A(Callback callback)
    :
    m_callback(callback)
    {}

    bool X
    (
        B& b
    ) const
    {
        if(m_callback(m_cache))
        {
            b.*M = m_cache;
            return true;
        }

        return false;
    }

protected:
    Callback m_callback;
    mutable typename std::remove_cvref<decltype(std::declval<B>().*M)>::type m_cache;
};

using FooA = A<&B::foo>;
using BarA = A<&B::bar>;

int main()
{
    FooA fooA([](int& f) { std::cout << "foo " << f << std::endl; ++f; return true; });
    BarA barA([](bool& b) { std::cout << "bar " << b << std::endl; b = !b; return true; });
    
    B b{.foo = 1, .bar = false};
    
    fooA.X(b);
    barA.X(b);
    fooA.X(b);
    barA.X(b);
    
    return 0;
};

错误输出

foo 0
bar 120
foo 1
bar 121

问题分析

  1. 未初始化的m_cache:m_cache是mutable成员,未在构造阶段赋值,初始值为内存垃圾值,导致第一次输出异常。
  2. 逻辑顺序错误:当前代码直接修改m_cache后赋值给b的成员,但正确流程应该是先将b的目标成员值读取到m_cache,再通过回调修改m_cache,最后写回b的成员。

修正后的代码

#include <functional>
#include <iostream>

struct B
{
    int foo;
    bool bar;
};

template<auto M>
class A
{
public:
    using Callback = std::function<bool(decltype(std::declval<B>().*M)&)>;

    explicit A(Callback callback)
        : m_callback(std::move(callback))
    {}

    bool X(B& b) const
    {
        // 先将b的目标成员值同步到cache
        m_cache = b.*M;
        if (m_callback(m_cache))
        {
            // 将修改后的cache写回b的成员
            b.*M = m_cache;
            return true;
        }
        return false;
    }

protected:
    Callback m_callback;
    mutable std::remove_cvref_t<decltype(std::declval<B>().*M)> m_cache;
};

using FooA = A<&B::foo>;
using BarA = A<&B::bar>;

int main()
{
    FooA fooA([](int& f) { std::cout << "foo " << f << std::endl; ++f; return true; });
    BarA barA([](bool& b) { std::cout << "bar " << b << std::endl; b = !b; return true; });
    
    B b{.foo = 1, .bar = false};
    
    fooA.X(b);
    barA.X(b);
    fooA.X(b);
    barA.X(b);
    
    return 0;
};

修正说明

  • 修复m_cache的初始值问题:在X函数开头先同步b的目标成员值到m_cache,确保回调操作的是当前实例的真实数据,而非内存垃圾值。
  • 简化类型声明:用std::remove_cvref_t替代typename std::remove_cvref<...>::type(C++14及以上支持),代码更简洁。
  • 构造函数优化:使用std::move转移回调对象所有权,避免不必要的拷贝;添加explicit关键字防止隐式转换,提升代码安全性。

正确输出

foo 1
bar 0
foo 2
bar 1

内容的提问来源于stack exchange,提问作者D.G. Redd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:42:09