使用声明和参数转发构造函数隐式复制结构
implicit copying of a struct with declard and argument-forwarding constructors
我想让一个结构用转发参数初始化它的成员。这编译并工作正常,除非我声明一个析构函数并且当我尝试 return 来自函数的结构(我认为这需要一个复制构造函数)。
#include <utility>
struct Foo
{
int val;
Foo(int val) : val(val)
{
}
};
struct FooContainer
{
Foo member;
template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}
~FooContainer() {}
};
FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}
int main() {}
编译器错误为:
example.cc: In constructor ‘FooContainer::FooContainer(Args&& ...) [with Args = FooContainer&]’:
example.cc:27: instantiated from here
example.cc:18: error: no matching function for call to ‘Foo::Foo(FooContainer&)’
example.cc:7: note: candidates are: Foo::Foo(int)
example.cc:4: note: Foo::Foo(const Foo&)
看起来它正在尝试为 FooContainer
生成复制构造函数但失败了,因为它没有初始化 Foo 的方法。然而,如果我删除 FooContainer
构造函数或析构函数,它可以正常编译。* 为什么要这样做?
无论如何,*在 http://cpp.sh/ 上使用 GCC 4.9.2。 Ubuntu 上的 g++ 4.4.3 即使未声明析构函数也会给出相同的错误。
我不能确切地告诉你为什么会发生这种情况(标准专家将能够)但问题实际上是因为你定义了一个用户定义的析构函数。
删除它,问题就消失了(无论如何你都想使用零规则,对吧?)
如果您必须拥有析构函数并且由于某种原因不能重构它,那么替换移动构造函数(您通过提供析构函数隐式删除了它)也可以解决它。
解决方案 1 - 使用规则 0:
#include <utility>
struct Foo
{
int val;
Foo(int val) : val(val)
{
}
};
struct FooContainer
{
Foo member;
template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}
// ~FooContainer() {}
};
FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}
int main() {}
解决方案 2 - 使用规则 5:
#include <utility>
struct Foo
{
int val;
Foo(int val) : val(val)
{
}
};
struct FooContainer
{
Foo member;
template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}
FooContainer(const FooContainer&) = default;
FooContainer(FooContainer&&) = default;
FooContainer& operator=(const FooContainer&) = default;
FooContainer& operator=(FooContainer&&) = default;
~FooContainer() {}
};
FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}
int main() {}
我想让一个结构用转发参数初始化它的成员。这编译并工作正常,除非我声明一个析构函数并且当我尝试 return 来自函数的结构(我认为这需要一个复制构造函数)。
#include <utility>
struct Foo
{
int val;
Foo(int val) : val(val)
{
}
};
struct FooContainer
{
Foo member;
template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}
~FooContainer() {}
};
FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}
int main() {}
编译器错误为:
example.cc: In constructor ‘FooContainer::FooContainer(Args&& ...) [with Args = FooContainer&]’:
example.cc:27: instantiated from here
example.cc:18: error: no matching function for call to ‘Foo::Foo(FooContainer&)’
example.cc:7: note: candidates are: Foo::Foo(int)
example.cc:4: note: Foo::Foo(const Foo&)
看起来它正在尝试为 FooContainer
生成复制构造函数但失败了,因为它没有初始化 Foo 的方法。然而,如果我删除 FooContainer
构造函数或析构函数,它可以正常编译。* 为什么要这样做?
*在 http://cpp.sh/ 上使用 GCC 4.9.2。 Ubuntu 上的 g++ 4.4.3 即使未声明析构函数也会给出相同的错误。
我不能确切地告诉你为什么会发生这种情况(标准专家将能够)但问题实际上是因为你定义了一个用户定义的析构函数。
删除它,问题就消失了(无论如何你都想使用零规则,对吧?)
如果您必须拥有析构函数并且由于某种原因不能重构它,那么替换移动构造函数(您通过提供析构函数隐式删除了它)也可以解决它。
解决方案 1 - 使用规则 0:
#include <utility>
struct Foo
{
int val;
Foo(int val) : val(val)
{
}
};
struct FooContainer
{
Foo member;
template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}
// ~FooContainer() {}
};
FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}
int main() {}
解决方案 2 - 使用规则 5:
#include <utility>
struct Foo
{
int val;
Foo(int val) : val(val)
{
}
};
struct FooContainer
{
Foo member;
template<typename... Args>
FooContainer(Args&&... args) :
member(std::forward<Args>(args)...)
{}
FooContainer(const FooContainer&) = default;
FooContainer(FooContainer&&) = default;
FooContainer& operator=(const FooContainer&) = default;
FooContainer& operator=(FooContainer&&) = default;
~FooContainer() {}
};
FooContainer getFooContainer()
{
FooContainer retval(0);
return retval;
}
int main() {}