VS2017(15.9.58)重载函数触发C2665错误求助
Visual Studio 2017重载函数C2665错误分析与解决
问题背景
在Visual Studio 2017(版本15.9.58)中,定义USE_FIRST_IMPLEM宏时,调用printPixelValues(const PgmImage&)会触发C2665编译错误,提示没有重载能匹配所有参数类型;不定义该宏则代码可正常运行。错误信息中出现了当前代码未定义的PixelValueT类型(来自未使用的ImageBuffer模板类),编译器似乎混淆了std::vector<GrayScalePixel>与ImageBuffer::container_t类型。
相关代码
#include <iostream> #include <vector> #include <iomanip> #include <cstdint> using GrayScalePixel = std::uint8_t; struct PgmImage { std::uint16_t Width; std::uint16_t Height; std::vector<GrayScalePixel> PixelValues; }; void printPixelValues(std::uint16_t width, std::uint16_t height, std::vector<GrayScalePixel>& pixelValues) { auto savedFillingChar = std::cout.fill('0'); for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { std::cout << std::setw(3) << (int)pixelValues[i * width + j] << " "; } std::cout << std::endl; } std::cout.fill(savedFillingChar); } #define USE_FIRST_IMPLEM #ifdef USE_FIRST_IMPLEM void printPixelValues(const PgmImage& pgmImage) { printPixelValues(pgmImage.Width, pgmImage.Height, pgmImage.PixelValues); } #else void printPixelValues(const PgmImage& pgmImage) { std::uint16_t width = pgmImage.Width; std::uint16_t height = pgmImage.Height; std::vector<GrayScalePixel> pixelValues = pgmImage.PixelValues; printPixelValues(width, height, pixelValues); } #endif
未使用的模板类定义:
template <typename PixelValueT> class ImageBuffer { public: using pixel_value_t = PixelValueT; using container_t = std::vector<PixelValueT>; // 其他未使用的成员 };
错误信息
error C2665: 'printPixelValues': none of the 2 overloads could convert all the argument types note: could be 'void printPixelValues(uint16_t,uint16_t,std::vector<PixelValueT,std::allocator<_Ty>> &)' with [ PixelValueT=GrayScalePixel, _Ty=GrayScalePixel ] note: while trying to match the argument list '(const uint16_t, const uint16_t, const std::vector<PixelValueT,std::allocator<_Ty>>)' with [ PixelValueT=GrayScalePixel, _Ty=GrayScalePixel ]
原因分析
- 核心错误原因:当定义
USE_FIRST_IMPLEM宏时,printPixelValues(const PgmImage&)接收的是const引用,因此pgmImage.PixelValues是const的std::vector。但被调用的 printPixelValues函数第三个参数是非const引用std::vector<GrayScalePixel>&,C++不允许将const对象绑定到非const引用,这才是编译错误的根源。 - 错误信息混淆原因:Visual Studio 2017的编译器存在bug,错误地将未使用的
ImageBuffer模板类中的PixelValueT类型别名代入错误信息,导致错误提示看起来像是类型混淆,但实际和ImageBuffer无关。
解决方案
方案一:修改函数参数为const引用(推荐)
由于printPixelValues函数内部仅读取像素值,不需要修改容器,直接将第三个参数改为const引用即可解决问题,同时避免不必要的拷贝:
void printPixelValues(std::uint16_t width, std::uint16_t height, const std::vector<GrayScalePixel>& pixelValues) { auto savedFillingChar = std::cout.fill('0'); for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { std::cout << std::setw(3) << (int)pixelValues[i * width + j] << " "; } std::cout << std::endl; } std::cout.fill(savedFillingChar); }
方案二:复制非const容器(避免拷贝开销不推荐)
如果无法修改原函数的参数类型,可以在printPixelValues(const PgmImage&)中复制一份非const的vector,就像宏未定义时的版本那样,但会产生额外的拷贝开销:
#ifdef USE_FIRST_IMPLEM void printPixelValues(const PgmImage& pgmImage) { std::vector<GrayScalePixel> pixelValues = pgmImage.PixelValues; printPixelValues(pgmImage.Width, pgmImage.Height, pixelValues); } #endif
内容的提问来源于stack exchange,提问作者Oodini
相关产品推荐
相关产品推荐

