类层次结构中的完美转发构造函数和复制构造函数之间的冲突 [英] Conflict between perfect forwarding constructor and copy constructor in class hierarchy

查看:347
本文介绍了类层次结构中的完美转发构造函数和复制构造函数之间的冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到一个问题,同时试图实现一个类层次结构与完美的转发构造函数。
考虑下面的例子:

  struct TestBase {
template< typename T&
explicit TestBase(T& t):s(std :: forward< T>(t)){} //编译器引用错误消息中的这一行

TestBase const TestBase& other):s(other.s){}

std :: string s;
};

struct Test:public TestBase {
template< typename T>
explicit test(T& t):TestBase(std :: forward< T>(t)){}

Test(const Test& other):TestBase }
};

当我尝试编译代码时,我得到以下错误:


错误3错误C2664:'std :: basic_string< _Elem,_Traits,_Alloc> :: basic_string(const std :: basic_string< _Elem,_Traits,_Alloc>& ':不能将参数1从'const Test'转换为'const std :: basic_string< _Elem,_Traits,_Alloc>&'


我的理解是,编译器将完美的转发构造函数视为一个比复制构造函数更好的数学。请参见例如 Scott Meyers:在C ++ 11中复制构造函数 a>。在没有类层次结构的其他实现中,我可以禁止完美的转发构造函数通过SFINAE作为复制构造函数。例如,请参见 Martinho Fernandes:转发构造函数的一些陷阱。当我尝试应用上述解决方案到这个例子我仍然不能编译与相同的错误消息。



我认为一个可能的解决方案是避免完美的转发,



所以我的问题是,如果有一些其他的解决方案,或者如果完美的转发在构造函数中的值,在这种情况下不可能?



更新:
原来我的问题很容易误解。所以我将尝试澄清我的意图和上下文一点。




  • 代码是完整的,像问题中发布。没有创建其他对象或调用函数。

  • 拥有完美的转发构造函数的目的是成员初始化,而不是 有一些额外的副本构造函数。这是为了在用临时对象初始化成员时保存一些对象副本(如Scott Meyers的演讲中所提出的)。

  • 不幸的是,完美的转发构造函数可能与其他重载的构造函数

  • 像这个问题的回答和注释建议:可能的解决方案是引入显式转换或具有单独的非模板化构造函数(即关于示例具有分别具有参数 const string& string&&& 的参数
  • b c> Test(const Test& other):TestBase(other){} code>到 Test(const Test& other):TestBase(static_cast< TestBase const&>(other)){}



    第二个测试构造函数调用TestBase,有两种可能性。其中一个采取任何东西,另一个采取TestBase。但是你通过一个测试 - 它的任何东西匹配更好。通过显式地转换到TestBase const&,我们应该能够得到正确的匹配。



    另一个可能性可能涉及如何构建Test - 也许你传递在匹配模板构造函数中测试?我们可以通过从Test中删除模板构造函数来测试这种可能性,并查看错误是否消失。



    如果是这样,为什么不会链接(在推导的类型匹配Test时禁用Test模板构造函数)work?


    I recently encountered a problem while trying to implement a class hierarchy with perfect forwarding constructors. Consider the following example:

    struct TestBase {
      template<typename T>
      explicit TestBase(T&& t) : s(std::forward<T>(t)) {} // Compiler refers to this line in the error message
    
      TestBase(const TestBase& other) : s(other.s) {}
    
      std::string s;
    };
    
    struct Test : public TestBase {
      template<typename T>
      explicit Test(T&& t) : TestBase(std::forward<T>(t)) {}
    
      Test(const Test& other) : TestBase(other) {}
    };
    

    When I try to compile the code I get the following error:

    Error 3 error C2664: 'std::basic_string<_Elem,_Traits,_Alloc>::basic_string(const std::basic_string<_Elem,_Traits,_Alloc> &)' : cannot convert parameter 1 from 'const Test' to 'const std::basic_string<_Elem,_Traits,_Alloc> &'

    My understanding is that the compiler treats the perfect forwarding constructor as a better math than the copy constructor. See for example Scott Meyers: Copying Constructors in C++11 . In other implementations without a class hierarchy I could disable the perfect forwarding constructor from being a copy constructor through SFINAE. See for example Martinho Fernandes: Some pitfalls with forwarding constructors. When I try to apply the mentioned solution to this example I still cannot compile with the same error message.

    I think one possible solution would be to avoid the perfect forwarding, take the parameters by value in the constructors and than move from them to the class variables.

    So my question is if there are some other solutions to this problem or if perfect forwarding in not possible in such a case?

    Update: It turned out that my question is easy to misunderstand. So I will try to clarify my intentions and the context a bit.

    • The code is complete like posted in the question. There are no other objects created or functions called. The error appeared while trying to compile the posted example.
    • The purpose of having the perfect forwarding constructor is for member initialization and not to have some kind of extra copy constructor. The reason here is to save some object copies when initializing members with temporary objects (as proposed in talks by Scott Meyers)
    • Unfortunately as it turned out perfect forwarding constructor can conflict with other overloaded constructors (in this example with the copy constructors).
    • Like the answers and comments to this question suggested: Possible solutions here would be to introduce explicit casts or having separate non-templated constructors (i.e. regarding the example having two constructors with parameters const string& and string&& respectively).

    解决方案

    Try changing Test(const Test& other) : TestBase(other) {} to Test(const Test& other) : TestBase(static_cast<TestBase const&>(other)) {}

    The 2nd Test constructor is calling TestBase, and there are two possibilities. One of them takes anything, the other takes a TestBase. But you are passing a Test to it -- the "anything" matches better. By explicitly casting to a TestBase const&, we should be able to get the right one to match.

    Another possibility might involve how Test is constructed -- maybe what you passed in matched the template constructor to Test instead? We can test this other possibility by removing the template constructor from Test and seeing if the error goes away.

    If that is the case, why wouldn't the technique you linked (to disable the Test template constructor when the type deduced matches Test) work?

    这篇关于类层次结构中的完美转发构造函数和复制构造函数之间的冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆