C构造函数:完美的转发和过载
我有两个类,A和B,B来自A.
A有多个构造函数(下例中为2). B有一个额外的成员要初始化(它有一个默认的初始化程序). 我怎样才能实现B可以使用A的构造函数之一构造,而不必手动重写B中A的所有构造函数重载? (在下面的例子中,我将不得不为B提供四个构造函数:B():A(){},B(字符串s):A(s){},B(int b):A(),p(b){},B(string s,int b):A(s),而不是只有两个,至少在忽略默认参数的可能性时). 我的方法是完美转发,但是,以下方案会导致错误: #include <utility> #include <string> struct A { A(const std::string& a) : name(a) {} A(){} virtual ~A(){} std::string name; }; struct B : public A { template<typename... Args> B(Args&&... args) : A(std::forward<Args>(args)...) {} B(const std::string& a,int b) : A(a),p(b) {} int p = 0; }; int main() { B b1("foo"); B b2("foobar",1); } 对于b2,GCC抱怨没有匹配函数来调用’A :: A(const char [5],int). 为什么看不到编译器的第二个构造函数而是调用它?有没有技术原因导致编译器无法找到B的正确构造函数? 确切的错误消息: main.cpp: In instantiation of 'B::B(Args&& ...) [with Args = {const char (&)[5],int}]': main.cpp:26:19: required from here main.cpp:15:54: error: no matching function for call to 'A::A(const char [5],int)' B(Args&&... args) : A(std::forward<Args>(args)...) {} ^ main.cpp:6:5: note: candidate: A::A() A(){} ^ main.cpp:6:5: note: candidate expects 0 arguments,2 provided main.cpp:5:5: note: candidate: A::A(const string&) A(const std::string& a) : name(a) {} ^ main.cpp:5:5: note: candidate expects 1 argument,2 provided main.cpp:4:8: note: candidate: A::A(const A&) struct A { ^ main.cpp:4:8: note: candidate expects 1 argument,2 provided 解决方法
“foobar”是一个const char(&)[7].因此Args比const std :: string&更好.
因此,选择了这个重载: template<typename... Args> B(Args&&... args) : A(std::forward<Args>(args)...) {} 其中Args是const char(&)[7] 所以它变成: B(const char (&&args_0) [7],int&& args_1) 转发给A的2参数构造函数…它不存在.
像这样的东西…… #include <utility> #include <string> struct A { A(std::string a) : name(std::move(a)) {} A(){} virtual ~A(){} std::string name; }; template<class...T> struct can_construct_A { template<class...Args> static auto test(Args&&...args) -> decltype(A(std::declval<Args>()...),void(),std::true_type()); template<class...Args> static auto test(...) -> std::false_type; using type = decltype(test(std::declval<T>()...)); static constexpr bool value = decltype(test(std::declval<T>()...))::value; }; struct B : public A { template<class...Args> B(std::true_type a_constructable,Args&&...args) : A(std::forward<Args>(args)...) {} template<class Arg1,class Arg2> B(std::false_type a_constructable,Arg1&& a1,Arg2&& a2) : A(std::forward<Arg1>(a1)),p(std::forward<Arg2>(a2)) { } template<typename... Args> B(Args&&... args) : B(typename can_construct_A<Args&&...>::type(),std::forward<Args>(args)...) {} int p = 0; }; int main() { B b1("foo"); B b2("foobar",1); }
简而言之(并且非常简单地说),当发生重载解析时,编译器会执行以下操作: >展开所有可能与给定参数匹配的模板化重载.将它们添加到列表中(权重指示到达此处所涉及的专业化级别). 编译器得到了一个.这不是递归搜索. 我向我们中的纯粹主义者道歉,他们会发现这种幼稚的解释令人反感:-) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- sqlite3的c/c++接口
- c – 在windbg中,如何在kernel32.dll中的所有函数
- 版本控制 – 在带有Pub的Dart中,何时应该对依赖项
- JSON.parse()和JSON.stringify()用法解析
- Match One of Many Characters (匹配多个字符中的
- Flex基础-----之DataProvider
- C#中的AttachmentCollection attachmentCollecti
- interface-builder – Swift – IBOutletCollect
- NoSQL数据库探讨
- 就NoSQL问题给mike.liu和liqingyuan朋友的回复