在我看来,你需要一些类型推导(概念?)。
编译器通常会使用该A(A const&)
版本,除非编写它的成员之一需要它A(A&)
。因此,我们可以包装一些小模板hackery 来检查每个成员拥有哪个版本的复制构造函数。
最新的
在ideone查阅它,或者在代码片段之后阅读 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。