コンテナのようなクラスを持っています。基礎となるタイプがmove-onlyであればmove-onlyですが、それ以外の場合はコピー可能です。それはそれは、テンプレートとテンプレート関数ができない作る必要があるため、私はコピーctorのわずかSFINAEことはできませんが、今テンプレートのパラメータに基づいてコピーコンストラクタを追加する
template<bool IsCopyable>
struct Foo
{
Foo();
Foo(const Foo&); // only include this when IsCopyable is true
Foo(Foo&&);
Foo& operator=(const Foo&); // only when IsCopyable
Foo& operator=(Foo&&);
};
:物事をシンプルにするために、のコピー可否は、単一のブールテンプレートパラメータによって決定されたと仮定しましょうコピーctorです。また、私は単にコピーctor内でstatic_assert()
を行うことはできません。これはコピーctorの誤った使い方をキャッチしますが、クラスを本質的に外部から構築可能にします(std::is_copy_constructible
型の特性は真となります)。
ところで、VC++ 2012でコンパイルする必要があるので、ファンシー表現SFINAEを使用することはできません.Ctors、デフォルト/削除された関数、またはconstexpr if
を継承しています(それにもかかわらず、 C++ 17私はまだそれを聞きたいです:))
明白な方法は、テンプレートの特殊化を使用することです。実際にはFooにはかなりの機能があり、私は自分自身を繰り返すのが好きではないので、私はむしろこのルートにはいきません。それにもかかわらず、これは私の唯一の選択肢に見えます。次のように基本クラスを使用してコードを共有することができます:
// Base functionality
template<bool IsCopyable>
struct FooBase
{
FooBase();
// move ctor and assignment can go here
FooBase(FooBase&&);
FooBase& operator=(FooBase&&);
// some generic conversion ctor and assignment that I happen to need
template<class T> FooBase(T&& t);
template<class T> FooBase& operator=(T&&);
// ... all sorts of functionality and datamembers
};
// Foo<false>
template<bool IsCopyable>
struct Foo : FooBase<IsCopyable>
{
// can't use inheriting ctors in VS 2012, wrap the calls manually:
Foo() { }
Foo(Foo&& other) : FooBase<IsCopyable>(std::move(other)) { }
Foo& operator=(Foo&& other)
{
FooBase<IsCopyable>::operator=(std::move(other));
return *this;
}
template<class T> Foo(T&& t) : FooBase<IsCopyable>(std::forward<T>(t)) { }
template<class T> Foo& operator=(T&& t)
{
FooBase<IsCopyable>::operator=(std::forward<T>(t));
return *this;
}
};
// Foo<true>
template<>
struct Foo<true> : FooBase<true>
{
// add these
Foo(const Foo&);
Foo& operator=(const Foo&);
// wrapping calls because of VS 2012:
Foo() { }
Foo(Foo&& other) : FooBase<true>(std::move(other)) { }
Foo& operator=(Foo&& other)
{
FooBase<true>::operator=(std::move(other));
return *this;
}
template<class T> Foo(T&& t) : FooBase<true>(std::forward<T>(t)) { }
template<class T> Foo& operator=(T&& t)
{
FooBase<true>::operator=(std::forward<T>(t));
return *this;
}
};
まだ少し冗長です。幸いにも、継承したctorsとデフォルトの関数を使用することができれば、より洗練されたものになります。それにもかかわらず、基本クラスを使用しない方が理想的です。
うわー!シンプルでエレガント。私はこのトリックを覚えておく必要があります。 – max66
C++ 11では、 "private method without definition"イディオムが古くなっている点を除いて、素晴らしい解決策です。これらのメソッドを明示的に削除しました。 –
@ArneVogel OPは削除された機能を使用できないと言います。 –