C构造函数:完美的转发和过载

C构造函数:完美的转发和过载,第1张

概述我有两个类,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), 我有两个类,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的第二个构造函数.

为什么看不到编译器的第二个构造函数而是调用它?有没有技术原因导致编译器无法找到B的正确构造函数?
我该如何解决这个问题?

确切的错误消息:

main.cpp: In instantiation of 'B::B(Args&& ...) [with Args = {const char (&)[5],int}]':main.cpp:26:19:   required from heremain.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 provIDedmain.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 provIDedmain.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参数构造函数…它不存在.

The wanted behavior is that if you construct a B with a constructor that works for A then the “…Args constructor” of B is called,otherwise another constructor of B gets called,otherwise it fails with “no appropriate constructor for B found”.

像这样的东西……

#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);}

After seeing that A doesn’t have a matching constructor,why doesn’t it go back and continue looking for other constructors of B that might match? Are there technical reasons?

简而言之(并且非常简单地说),当发生重载解析时,编译器会执行以下 *** 作:

>展开所有可能与给定参数匹配的模板化重载.将它们添加到列表中(权重指示到达此处所涉及的专业化级别).
>将任何具体的重载添加到列表中,通过合法地将转换运算符应用于参数,并使用权重指示将提供的参数转换为函数参数类型所需的转换次数.
>通过提升“工作”或重量对列表进行排序.
>选择需要最少工作的人.如果有一个最好的领带,错误.

编译器得到了一个.这不是递归搜索.

我向我们中的纯粹主义者道歉,他们会发现这种幼稚的解释令人反感:-)

总结

以上是内存溢出为你收集整理的C构造函数:完美的转发和过载全部内容,希望文章能够帮你解决C构造函数:完美的转发和过载所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/1221439.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存