gpt4 book ai didi

c++ - 转换构造函数调用 move 但不调用 copy

转载 作者:行者123 更新时间:2023-11-30 04:06:52 25 4
gpt4 key购买 nike

使用此代码:

template <class T> class Test {
T _temp;

public:
Test() {
std::cout << "Test()" << std::endl;
};

template <class T2> Test(Test<T2> const &test) {
std::cout << "template <class T2> Test(Test<T2> const &test)" << std::endl;
};

template <class T2> Test(Test<T2> &&test) {
std::cout << "template <class T2> Test(Test<T2> &&test)" << std::endl;
};

};

使用此测试代码:

Test<int> testInt;
Test<float> testFloat(testInt);
Test<float> testFloat2(std::move(testInt));

std::cout << "----------" << std::endl;

Test<int> testInt2;
Test<int> testInt3(testInt2);
Test<int> testInt4(std::move(testInt2));

产生这个输出:

Test()
template <class T2> Test(Test<T2> const &test)
template <class T2> Test(Test<T2> &&test)
----------
Test()

当使用相同的类型时,使用默认的复制和移动构造函数代替转换构造函数。

但是如果我在类中添加默认复制构造函数:

Test(Test const &test) = default;

它产生这个输出:

Test()
template <class T2> Test(Test<T2> const &test)
template <class T2> Test(Test<T2> &&test)
----------
Test()
template <class T2> Test(Test<T2> &&test)

移动转换构造函数即使是相同的类型也会被调用,为什么?

有没有办法统一复制和转换构造函数来避免重复代码?

最佳答案

添加隐式生成的(= 编译器生成的)移动构造函数的规则非常保守:只有在安全的情况下才添加一个。如果用户定义了复制构造函数,编译器就不能假设添加一些简单的编译器生成的移动构造函数仍然是安全的,因此不会添加任何移动构造函数。 实际上,声明它足以阻止移动构造函数的生成,IIRC 允许仅复制类型。

构造函数模板永远不会被视为复制构造函数或移动构造函数,因此它们不会阻止隐式生成这些构造函数。

当然,如果从未声明移动构造函数,则可以通过重载决议选择另一个构造函数。考虑这个例子:

#include <iostream>
#include <utility>

struct loud
{
loud() { std::cout << "default ctor\n"; }
loud(loud const&) { std::cout << "copy ctor\n"; }
loud(loud&&) { std::cout << "move ctor\n"; }
};

struct foo
{
loud l;
};

struct bar
{
loud l;
bar() = default;
bar(bar const&) = default;
};

int main()
{
foo f0;
foo f1(f0);
foo f2(std::move(f0));

std::cout << "--------------\n";

bar b0;
bar b1(b0);
bar b2(std::move(b0));
}

输出:

default ctorcopy ctormove ctor--------------default ctorcopy ctorcopy ctor

Here, foo will get implicitly declared default, copy and move constructors, whereas bar won't get an implicitly declared move constructor, since it has user-declared copy constructor.


In your second case, there's no implicitly-declared move constructor, therefore overload resolution for Test<int> testInt4(std::move(testInt2)) prefers the constructor template to the copy constructor, since the former takes a reference that's less cv-qualified.


To reduce code duplication, you could delegate construction:

template <class T>
class Test {
T _temp;

struct tag {};

public:
Test() {
std::cout << "Test()" << std::endl;
};

Test(Test const& test)
: Test(test, tag{})
{}

Test(Test&& test)
: Test(std::move(test), tag{})
{}

template <class T2> Test(Test<T2> const &test, tag = {}) {
std::cout << "template <class T2> Test(Test<T2> const &test)" << std::endl;
};

template <class T2> Test(Test<T2> &&test, tag = {}) {
std::cout << "template <class T2> Test(Test<T2> &&test)" << std::endl;
};

};

顺便说一句,您还可以通过使用完美转发构造函数模板而不是两个构造函数模板来减少一些样板:

使用这个特性:

template<class T>
struct is_Test : std::false_type {};
template<class T>
struct is_Test<Test<T>> : std::true_type {};

您可以定义:

    template <class T2,
class = typename std::enable_if<is_Test<T2>::value>::type>
Test(T2&& test, tag = {}) {
std::cout << "template <class T2> Test(T2&& test)" << std::endl;
};

关于c++ - 转换构造函数调用 move 但不调用 copy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22750070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com