为何使用初始化列表调用DataHandler构造函数会出现歧义?
构造函数调用歧义的原因分析与解决
歧义产生的核心逻辑
当你写DataHandler dh({trainCsv, testCsv});时,编译器会同时考虑两个构造函数的匹配可能性,且两者的转换代价相同,导致无法抉择:
- 匹配第二个构造函数:初始化列表
{trainCsv, testCsv}可以直接隐式构造std::vector<fs::path>,这是一次用户定义转换(调用vector的初始化列表构造函数),符合DataHandler(const std::vector<fs::path>&)的参数要求。 - 匹配第一个构造函数:虽然第一个构造函数被
explicit修饰,但这仅阻止复制初始化(如DataHandler dh = {...};),不影响直接初始化。编译器会尝试用初始化列表构造临时的fs::path对象——std::filesystem::path提供了一个模板构造函数template<class Source> path(const Source&, format),该模板能匹配std::initializer_list<fs::path>作为输入(尽管语义上这并不合理,但语法层面是合法的),因此这也是一次用户定义转换,符合DataHandler(const fs::path&)的参数要求。
由于这两个转换的优先级相同,编译器无法判断你期望调用哪个构造函数,从而抛出歧义错误。
解决方法
你可以通过以下方式消除歧义:
- 显式指定类型:明确告诉编译器要构造
std::vector<fs::path>:DataHandler dh(std::vector<fs::path>{trainCsv, testCsv}); - 新增初始化列表构造函数:给
DataHandler添加一个直接接受std::initializer_list<fs::path>的构造函数,让初始化列表得到精确匹配:class DataHandler { public: explicit DataHandler(const fs::path & dataPath); DataHandler(const std::vector<fs::path> &dataPaths); DataHandler(std::initializer_list<fs::path> paths) : DataHandler(std::vector<fs::path>(paths)) {} // 复用vector版本的逻辑 // ... }; - 提前构造容器:像你注释掉的代码那样,先构造好
std::vector<fs::path>再传入,避免初始化列表的模糊匹配:DataHandler dh(dataPaths);
内容的提问来源于stack exchange,提问作者trozzel
相关产品推荐
相关产品推荐

