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

Visual Studio 2022中C++代码报错解决方案咨询

解决Visual Studio 2022中C++加载Excel数据集的编译错误

错误根源与核心解决步骤

你遇到的一系列编译错误(标识符未定义、缺少括号、结构化绑定需要C17),核心原因是**项目未启用C17编译标准**——结构化绑定是C++17引入的特性,VS2022默认可能未开启该标准,导致编译器无法识别for (const auto& [otherUser, ratings] : userRatings)这类语法,进而引发连锁错误。

启用C++17标准的操作步骤:

  • 右键项目 → 选择「属性」
  • 导航到「配置属性」→「C/C++」→「语言」
  • 在「C标准」下拉菜单中选择「ISO C17标准(/std:c++17)」
  • 点击「确定」保存配置,重新编译项目

其他潜在问题修正

除了编译标准问题,代码中还有几个需要注意的问题,避免运行时错误:

  1. 向量索引越界风险
    代码中ratings[movie]直接使用传入的movie值作为索引,但std::vector索引从0开始。如果你的Excel表格中,用户ID列是第1列,电影评分从第2列开始,那么movie=3对应的是ratings[2]而非ratings[3]。需要根据实际数据结构调整索引对应关系,或者在函数中做偏移处理:

    prediction += similarity * ratings[movie - 1]; // 假设movie从1开始计数
    
  2. 余弦相似度的长度一致性检查
    cosineSimilarity函数假设两个用户的评分向量长度完全一致,如果Excel中存在行数不一致的情况,会导致数组越界。可以在函数开头添加检查:

    if (user1.size() != user2.size()) {
        throw std::invalid_argument("用户评分向量长度必须一致");
        // 或者返回0.0等默认值
    }
    
  3. 除以零的异常处理
    如果所有其他用户与目标用户的相似度都不大于0,sumSimilarities会等于0,导致prediction / sumSimilarities出现除以零的错误。需要添加判断:

    if (sumSimilarities == 0.0) {
        // 返回默认值,比如所有评分的平均值,或者目标用户的平均评分
        return 0.0; // 可根据需求调整
    }
    return prediction / sumSimilarities;
    

修正后的完整代码

#include <iostream>
#include <map>
#include <vector>
#include <cmath>
#include <stdexcept>

#include <xlnt/xlnt.hpp>

// 用户评分的类型别名:用户ID -> 评分向量
using UserRatings = std::map<int, std::vector<double>>;

// 计算两个用户的余弦相似度
double cosineSimilarity(const std::vector<double>& user1, const std::vector<double>& user2) {
    if (user1.size() != user2.size()) {
        throw std::invalid_argument("用户评分向量长度必须一致");
    }

    double dotProduct = 0.0;
    double magnitude1 = 0.0;
    double magnitude2 = 0.0;

    for (size_t i = 0; i < user1.size(); i++) {
        dotProduct += user1[i] * user2[i];
        magnitude1 += user1[i] * user1[i];
        magnitude2 += user2[i] * user2[i];
    }

    // 避免开根号时出现0的情况
    if (magnitude1 == 0.0 || magnitude2 == 0.0) {
        return 0.0;
    }

    return dotProduct / (sqrt(magnitude1) * sqrt(magnitude2));
}

// 预测用户对某部电影的评分
double predictRating(const UserRatings& userRatings, int user, int movie) {
    double prediction = 0.0;
    double sumSimilarities = 0.0;

    // 检查目标用户是否存在
    if (userRatings.find(user) == userRatings.end()) {
        throw std::invalid_argument("目标用户不存在");
    }

    const std::vector<double>& targetRatings = userRatings.at(user);
    // 检查movie索引是否合法(假设movie从1开始计数)
    if (movie < 1 || static_cast<size_t>(movie) > targetRatings.size()) {
        throw std::invalid_argument("电影索引不合法");
    }

    for (const auto& [otherUser, ratings] : userRatings) {
        if (otherUser == user) continue;

        try {
            double similarity = cosineSimilarity(targetRatings, ratings);
            if (similarity > 0) {
                sumSimilarities += similarity;
                prediction += similarity * ratings[movie - 1]; // 转换为0-based索引
            }
        } catch (const std::invalid_argument& e) {
            std::cerr << "跳过用户 " << otherUser << ":" << e.what() << std::endl;
            continue;
        }
    }

    if (sumSimilarities == 0.0) {
        std::cerr << "未找到相似用户,返回默认评分0.0" << std::endl;
        return 0.0;
    }

    return prediction / sumSimilarities;
}

int main() {
    try {
        xlnt::workbook workbook;
        workbook.load("ratings.xlsx");
        xlnt::worksheet sheet = workbook.active_sheet();

        UserRatings userRatings;
        for (auto row : sheet.rows()) {
            // 跳过表头行(如果Excel有表头)
            if (row[0].is_string()) {
                continue;
            }

            int user = row[0].value<int>();
            std::vector<double> ratings;
            for (auto cell : row) {
                // 跳过用户ID列(column()返回1-based列号)
                if (cell.column() == 1) continue;
                ratings.push_back(cell.value<double>());
            }
            userRatings[user] = ratings;
        }

        // 预测用户1对电影3的评分(movie从1开始计数)
        double prediction = predictRating(userRatings, 1, 3);
        std::cout << "用户1对电影3的预测评分:" << prediction << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "错误:" << e.what() << std::endl;
        return 1;
    }

    return 0;
}

xlnt库配置说明

确保你已经正确配置xlnt库:

  • 在项目属性的「C/C++」->「常规」->「附加包含目录」中添加xlnt的头文件路径
  • 在「链接器」->「常规」->「附加库目录」中添加xlnt的库文件路径
  • 在「链接器」->「输入」->「附加依赖项」中添加xlnt.lib(Debug版本可能是xlntd.lib)

内容的提问来源于stack exchange,提问作者Hamdi Al-Akkad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:15:51