考虑这一情况:
template<typename T>
struct A {
A(A ???&) = default;
A(A&&) { /* ... */ }
T t;
};我显式地声明了一个移动构造函数,所以如果我想要一个未删除的复制构造函数,我需要显式声明一个复制构造函数。如果我想default它,我如何才能找到正确的参数类型?
A(A const&) = default; // or
A(A &) = default; // ?我还感兴趣的是,您是否遇到了这样的场景在实际程序中出现的情况。说明书上写着
一个明确默认的函数将..。
如果隐式声明的复制构造函数将具有A &类型,则我希望使用参数类型A &显式地默认复制构造函数。但是,如果隐式声明的复制构造函数将具有参数类型A const&,则我不希望显式默认复制构造函数具有参数类型A &,因为这将禁止从const复制。
我不能声明这两个版本,因为如果隐式声明的函数具有参数类型A &,而我的显式默认声明具有参数类型A const&,这将违反上述规则。据我所见,只有当隐式声明为A const&,而显式声明为A &时,才允许出现差异。
编辑:事实上,规范说
如果一个函数在其第一次dec- laration中被显式默认,.
因此,我需要定义这些类外(我认为这并不伤人,因为就我所能看到的唯一区别是,这个函数将变得非平凡,在这些情况下这可能是很可能的)。
template<typename T>
struct A {
A(A &);
A(A const&);
A(A&&) { /* ... */ }
T t;
};
// valid!?
template<typename T> A<T>::A(A const&) = default;
template<typename T> A<T>::A(A &) = default;好的,如果显式声明的函数是A const&,那么它是无效的,而隐式声明是A &。
用户提供的显式默认函数(即,在其第一次声明后显式默认)将在显式默认的位置定义;如果此函数被隐式定义为已删除,则程序的格式不正确。
这与GCC的做法相吻合。现在,我如何实现我原来的目标--匹配隐式声明的构造函数的类型?
发布于 2011-05-29 15:22:44
在我看来,你需要某种类型的推论(概念?)。
编译器通常会使用A(A const&)版本,除非其中一个成员需要它编写A(A&)。因此,我们可以包装一些小的模板黑客,以检查每个成员的复制构造函数的哪个版本。
最新
在意为上查阅它,或者在代码片段之后由Clang读取错误。
#include <memory>
#include <type_traits>
template <bool Value, typename C>
struct CopyConstructorImpl { typedef C const& type; };
template <typename C>
struct CopyConstructorImpl<false,C> { typedef C& type; };
template <typename C, typename T>
struct CopyConstructor {
typedef typename CopyConstructorImpl<std::is_constructible<T, T const&>::value, C>::type type;
};
// Usage
template <typename T>
struct Copyable {
typedef typename CopyConstructor<Copyable<T>, T>::type CopyType;
Copyable(): t() {}
Copyable(CopyType) = default;
T t;
};
int main() {
{
typedef Copyable<std::auto_ptr<int>> C;
C a; C const b;
C c(a); (void)c;
C d(b); (void)d; // 32
}
{
typedef Copyable<int> C;
C a; C const b;
C c(a); (void)c;
C d(b); (void)d;
}
}这意味着:
6167745.cpp:32:11: error: no matching constructor for initialization of 'C' (aka 'Copyable<std::auto_ptr<int> >')
C d(b); (void)d;
^ ~
6167745.cpp:22:7: note: candidate constructor not viable: 1st argument ('const C' (aka 'const Copyable<std::auto_ptr<int> >')) would lose const qualifier
Copyable(CopyType) = default;
^
6167745.cpp:20:7: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
Copyable(): t() {}
^
1 error generated.前版
这是我能想到的最好的:
#include <memory>
#include <type_traits>
// Usage
template <typename T>
struct Copyable
{
static bool constexpr CopyByConstRef = std::is_constructible<T, T const&>::value;
static bool constexpr CopyByRef = !CopyByConstRef && std::is_constructible<T, T&>::value;
Copyable(): t() {}
Copyable(Copyable& rhs, typename std::enable_if<CopyByRef>::type* = 0): t(rhs.t) {}
Copyable(Copyable const& rhs, typename std::enable_if<CopyByConstRef>::type* = 0): t(rhs.t) {}
T t;
};
int main() {
{
typedef Copyable<std::auto_ptr<int>> C; // 21
C a; C const b; // 22
C c(a); (void)c; // 23
C d(b); (void)d; // 24
}
{
typedef Copyable<int> C; // 27
C a; C const b; // 28
C c(a); (void)c; // 29
C d(b); (void)d; // 30
}
}这几乎有效..。但我在构建"a“时遇到了一些错误。
6167745.cpp:14:78: error: no type named 'type' in 'std::enable_if<false, void>'
Copyable(Copyable const& rhs, typename std::enable_if<CopyByConstRef>::type* = 0): t(rhs.t) {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
6167745.cpp:22:11: note: in instantiation of template class 'Copyable<std::auto_ptr<int> >' requested here
C a; C const b;
^和:
6167745.cpp:13:67: error: no type named 'type' in 'std::enable_if<false, void>'
Copyable(Copyable& rhs, typename std::enable_if<CopyByRef>::type* = 0): t(rhs.t) {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
6167745.cpp:28:11: note: in instantiation of template class 'Copyable<int>' requested here
C a; C const b;
^这两种情况发生的原因是相同的,我不明白为什么。编译器似乎试图实现所有的构造函数,即使我有一个默认的构造函数。我原以为SFINAE会申请,但似乎不适用。
但是,正确地检测到第24行错误:
6167745.cpp:24:11: error: no matching constructor for initialization of 'C' (aka 'Copyable<std::auto_ptr<int> >')
C d(b); (void)d;
^ ~
6167745.cpp:13:7: note: candidate constructor not viable: 1st argument ('const C' (aka 'const Copyable<std::auto_ptr<int> >')) would lose const qualifier
Copyable(Copyable& rhs, typename std::enable_if<CopyByRef>::type* = 0): t(rhs.t) {}
^
6167745.cpp:11:7: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
Copyable(): t() {}
^在这里,我们可以看到,CopyByConstRef被正确地驱逐出超载集,希望感谢SFINAE。
发布于 2011-05-29 13:06:13
我想我看不出问题..。这与实现副本构造函数的常见情况有什么不同?
如果复制构造函数不会修改参数(并且隐式定义的复制构造函数不会修改),那么参数应该作为常量引用传递。对于不使用常量引用的复制构造函数,我知道的唯一用例是,在C++03中,您想要实现移动la std::auto_ptr,这通常是个坏主意。在C++0x中,移动将像使用移动构造函数一样实现。
发布于 2011-05-29 13:05:22
我从未见过隐式复制构造函数为A&的情况--在任何情况下,使用const A&都应该是好的。
https://stackoverflow.com/questions/6167745
复制相似问题