何らかの型推論 (概念?) が必要になるように思えます。
コンパイラはA(A const&)
、それが書かれているメンバーのいずれかによって必要とされない限り、通常、バージョンを使用しA(A&)
ます。したがって、いくつかの小さなテンプレート ハッカーをラップして、各メンバーが持つコピー コンストラクターのバージョンを確認できます。
最新
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() {}
^
うまくいけば SFINAE のおかげで、CopyByConstRef がオーバーロード セットから正しく削除されたことがわかります。