テンプレートに基づいてメンバーを持っている、または持っていないクラスを持つことはできますか?架空のコード:
template <typename HasBazMember=true>
class Foo {
int bar;
ConditionallyHaveMember<int, HasBazMember> baz;
};
したがって、上記では、Fooにメンバー「baz」を持たせ、Fooには持たせないようにします。
特殊化なしのC++11のソリューション:
class empty {};
template <typename T>
struct wrap { T wrapped_member; };
template <bool HasBazMember=true>
class Foo : private std::conditional<HasBazMember, wrap<int>, empty>::type {
public:
int bar;
int& baz() {
static_assert(HasBazMember, "try using baz without HasBaz");
return static_cast<wrap<int>&>(*this).wrapped_member;
}
};
int main()
{
Foo<true> t;
t.baz() = 5;
Foo<false> f;
f.baz() = 5; // ERROR
}
EBOのおかげで、の場合はスペースのオーバーヘッドがないことに注意してくださいHasBazMember=false
。
はい、できますが、クラス全体を専門にする必要があります。例:
template< bool HasBazMember = true >
class Foo {
int bar;
int baz;
};
template<>
class Foo< false > {
int bar;
};
ロジックを分離できる場合は、それらのメンバーを基本クラスに配置して、クラス全体のコードを複製する必要がないようにすることができます。例えば、
template< bool HasBazMember >
class FooBase
{
protected:
int baz;
};
template<>
class FooBase< false >
{
// empty class
// the Empty Base Optimization will make this take no space when used as a base class
};
template< bool HasBazMember = true >
class Foo : FooBase< HasBazMember >
{
int bar;
};
またはBoost.CompressedPairを使用します:
struct empty {};
template< bool HasBazMember = true >
class Foo
{
boost::compressed_pair<
int
, typename std::conditional< HasBazMember, int, empty >::type
> bar_and_maybe_baz_too;
};