如何让编译器区分poly(double...)与poly(int, double...)构造函数?
多项式类构造函数重载歧义问题的解决方法
问题背景
我正在编写一个处理多项式的小型库,核心类为poly,包含4个重载构造函数用于表示单个多项式。
在./test-poly/test-all.cpp中尝试创建poly对象:
poly::poly my_poly = poly::poly((double)6.0, -2.0, 4.0);
poly类的构造函数声明如下:
// 仅用数值创建多项式 poly(double values...); // 使用vector<double>创建多项式 poly(vector<double> values); // 非零底数的多项式构造 poly(int base, double values...); // 非零底数+vector<double>的多项式构造 poly(int base, vector<double> values);
编译时触发构造函数歧义错误:
./test-all.cpp:20:63: error: call of overloaded ‘poly(double, double, double)’ is ambiguous 20 | poly::poly my_poly = poly::poly((double)6.0, -2.0, 4.0); | ^ In file included from ./test-all.cpp:3: ././../polynomial-lib/polynomial.hpp:22:17: note: candidate: ‘poly::poly::poly(int, double, ...)’ 22 | poly(int base, double values...); | ^~~~ ././../polynomial-lib/polynomial.hpp:16:17: note: candidate: ‘poly::poly::poly(double, ...)’ 16 | poly(double values...); | ^~~~
我清楚编译器无法确定调用哪个构造函数,希望保留这4个poly构造函数的方案,虽然可以将其中2个改为构建器函数,但我不喜欢这种方式:
// 创建非零底数的多项式 poly special_poly(int base, double values...){ poly temp_poly = poly(values...); temp_poly.set_base(base); return temp_poly; } // 创建非零底数+vector<double>的多项式 poly special_poly(int base, vector<double> values){ poly temp_poly = poly(values); temp_poly.set_base(base); return temp_poly; }
请问有没有无需使用构建器函数的解决方法?
可行的解决方法
1. 引入标记类型明确构造逻辑
定义一个空的标记结构体,用来区分“带底数”和“不带底数”的构造场景:
struct WithBaseTag {}; constexpr WithBaseTag with_base;
修改带底数的构造函数,将标记作为第一个参数:
// 非零底数的多项式构造 poly(WithBaseTag, int base, double values...); // 非零底数+vector<double>的多项式构造 poly(WithBaseTag, int base, vector<double> values);
创建对象时通过标记明确指定构造函数:
// 不带底数的构造调用 poly my_poly(6.0, -2.0, 4.0); // 带底数的构造调用 poly my_poly_with_base(with_base, 2, 6.0, -2.0, 4.0);
这种方式通过参数类型的差异彻底消除了歧义,同时代码可读性也得到提升。
2. 用初始化列表替换可变参数(推荐)
C++的C风格可变参数...存在类型安全隐患,且容易引发重载歧义。建议将接受多个数值的构造函数改为使用std::initializer_list<double>:
// 仅用数值创建多项式 poly(std::initializer_list<double> values); // 非零底数的多项式构造 poly(int base, std::initializer_list<double> values);
调用时的语法更清晰,也不会有歧义:
// 不带底数 poly my_poly({6.0, -2.0, 4.0}); // 带底数 poly my_poly_with_base(2, {6.0, -2.0, 4.0});
这种方案不仅解决了歧义问题,还能在编译时检查参数类型,是更现代、更安全的C++写法。
3. 显式强制指定构造函数(不推荐)
如果坚持保留原始的可变参数构造函数,可以通过显式类型转换来消除歧义,但这种写法可读性极差,不建议使用:
// 强制调用第一个可变参数构造函数 poly my_poly = static_cast<poly(*)(double, double, double)>(&poly::poly)(6.0, -2.0, 4.0);
内容的提问来源于stack exchange,提问作者Bartłomiej Konecki
相关产品推荐
相关产品推荐

