使用-pedantic编译时,含std::reference_wrapper构造函数的类存在构造歧义
解决包含拷贝构造函数与
std::reference_wrapper构造函数的歧义问题 这是个典型的重载匹配歧义问题,咱们先拆解原因,再给出可行的解决方案。
首先看你提供的代码:
#include <functional> #include <iostream> class Class { public: Class() { std::cout << "Class()" << std::endl; } Class(Class const &) { std::cout << "Class(Class const &)" << std::endl; } Class(std::reference_wrapper<Class>) { std::cout << "Class(std::reference_wrapper<Class>)" << std::endl; } Class(std::reference_wrapper<const Class>); };
为什么会出现歧义?
当你尝试用Class类型的对象(无论const还是非const)初始化另一个Class实例时,编译器会在两个构造函数间陷入纠结:
- 拷贝构造函数:接受
const Class&,不管你传的是const还是非const对象,都能匹配(非const对象可隐式转换为const Class&)。 std::reference_wrapper构造函数:std::reference_wrapper自带从T&的隐式构造函数,编译器可以把你的Class对象隐式转换成std::reference_wrapper<Class>(或const版本),再调用对应构造函数。
这两个构造函数的匹配优先级完全相同,编译器无法自动选择,在-pedantic严格编译模式下,这类模糊匹配会被明确抛出歧义错误。
解决方案
方案一:添加explicit关键字(推荐)
最直接且易维护的方式是给std::reference_wrapper相关的构造函数加上explicit,禁止隐式转换触发该构造:
#include <functional> #include <iostream> class Class { public: Class() { std::cout << "Class()" << std::endl; } Class(Class const &) { std::cout << "Class(Class const &)" << std::endl; } // 加上explicit,避免隐式转换触发此构造 explicit Class(std::reference_wrapper<Class>) { std::cout << "Class(std::reference_wrapper<Class>)" << std::endl; } // 完善const版本的构造实现(你之前仅做了声明) explicit Class(std::reference_wrapper<const Class>) { std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl; } }; int main() { Class obj; Class obj1(obj); // 明确调用拷贝构造函数 Class obj2(std::ref(obj)); // 显式用std::ref触发reference_wrapper构造 const Class cobj; Class obj3(cobj); // 调用拷贝构造 Class obj4(std::cref(cobj)); // 显式用std::cref触发const版本构造 }
修改后,只有当你**显式使用std::ref或std::cref**时,才会调用std::reference_wrapper对应的构造函数;日常对象拷贝会直接走拷贝构造,完全避免歧义。
方案二:用SFINAE约束匹配范围(进阶)
如果你确实需要保留隐式转换能力,可以用SFINAE(Substitution Failure Is Not An Error)来精准约束构造函数的匹配范围,确保仅当参数是明确的std::reference_wrapper时才匹配:
#include <functional> #include <iostream> #include <type_traits> class Class { public: Class() { std::cout << "Class()" << std::endl; } Class(Class const &) { std::cout << "Class(Class const &)" << std::endl; } // 仅当T为非const Class时匹配 template <typename T, typename = std::enable_if_t<std::is_same_v<T, Class>>> Class(std::reference_wrapper<T>) { std::cout << "Class(std::reference_wrapper<Class>)" << std::endl; } // 仅当T为const Class时匹配 template <typename T, typename = std::enable_if_t<std::is_same_v<T, const Class>>> Class(std::reference_wrapper<T>) { std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl; } };
这种方式能让编译器在匹配时更精准,避免把普通Class对象误判为可转换的reference_wrapper。
通常来说,第一种explicit方案更简单直观,也符合C++“避免意外隐式转换”的设计原则。
内容的提问来源于stack exchange,提问作者zennehoy
相关产品推荐
相关产品推荐

