テンプレートクラスFoo
には2つのバリエーションがあります。私は、クラスに、そのパラメータが存在するときに、クラスにメンバー変数を格納し、そのためのいくつかのゲッターとセッターを提供するいくつかの追加の機能を持たせたい。私はまた、追加のタイプについて追加のstatic_assert()
を実行する必要があります。また、通常のコンストラクタを無効にし、そのタイプのパラメータも持つものを提供する必要があります。これは次のようになります。継承またはクラスの特殊化を使用せずにメンバー関数と変数を無効にする
template <class Irrelevant, class Extra>
class Foo {
//other stuff...
static_assert(is_good_v<Extra>);
Extra extra;
public:
//other stuff...
Foo(Irrelevant i) {/* irrelevant */}
//now methods I need to enable only when Extra is present
Foo(Irrelevant i, Extra e) : extra(e) {/* irrelevant */}
void setExtra(Extra e) {extra = e;}
void getExtra() {return extra;}
};
私はいくつかのアプローチを試みましたが、満足できるものはありませんでした。まず私は、継承を使用しようとしました:
template <class Irrelevant>
class Bar {
//other stuff...
public:
//other stuff...
Foo(Irrelevant i) {/* irrelevant */}
};
template <class Irrelevant, class Extra>
class Foo : public Bar<Irrelevant> {
static_assert(is_good_v<Extra>);
Extra extra;
public:
Foo(Irrelevant i, Extra e) : Bar<Irrelevant>(i), extra(e) {/* irrelevant */}
void setExtra(Extra e) {extra = e;}
void getExtra() {return extra;}
};
template <class Irrelevant>
class Foo : public Bar<Irrelevant> {};
この(または似たような、少なくとも)が一人で働いていたが、どこか別の場所にそれらの上にテンプレートチェックを行う際に、余分な回避策が必要であり、またそれが不必要にグローバル名前空間を散らばって、私は「shouldnそれをやっている。 第二のアプローチは、このように、Foo
の特殊化を行うことでした。
template <class Irrelevant, class... T>
class Foo {};
template <class Irrelevant, class Extra>
class Foo<Irrelevant, Extra> {
//other stuff...
static_assert(is_good_v<Extra>);
Extra extra;
public:
//other stuff...
Foo(Irrelevant i) {/* irrelevant */}
//now methods I need to enable only when Extra is present
Foo(Irrelevant i, Extra e) : extra(e) {/* irrelevant */}
void setExtra(Extra e) {extra = e;}
void getExtra() {return extra;}
};
template <class Irrelevant>
class Foo<Irrelevant> {
//other stuff...
public:
//other stuff...
Foo(Irrelevant i) {/* irrelevant */}
};
、これも働いていた、とごみグローバル名前空間をしなかったが、//other stuff
の全ては、その偉大されていない、重複しました。私が試したかった3番目のアプローチは、そのすべてのものをstd::enable_if
にすることですが、それを動作させることはできません。私はこのような何か試してみました:
template <class Irrelevant, class Extra = void>
class Foo {
//other stuff...
static constexpr bool hasExtra = std::is_same_v<Extra, void>;
static_assert(!hasExtra || is_good_v<Extra>);
std::conditional<hasExtra, Extra, bool> extra;
public:
//other stuff...
template <typename = typename std::enable_if_t<!hasExtra>>
Foo(Irrelevant i) {/* irrelevant */}
//now methods I need to enable only when Extra is present
template <typename = typename std::enable_if_t<hasExtra>>
Foo(Irrelevant i, Extra e) : extra(e) {/* irrelevant */}
template <typename = typename std::enable_if_t<hasExtra>>
void setExtra(Extra e) {extra = e;}
template <typename = typename std::enable_if_t<hasExtra>>
void getExtra() {return extra;}
};
をしかしSFINAEはゲッターとセッターをコンパイルするときにその方法をSFINAEする他の機能を持っていないとして、それはコンパイルエラーを生成するので、これは明らかに動作しません。 Extra == void
のときにダミー関数を追加すると、誰かがそれらの関数をコンパイルするコードを作ることになります。どうしたらいいですか?
のようなものをあなたは_mixins_ではなく、[CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)を使用する必要がある場合。 – user0042
私は書きましたが、Foo以外の名前をグローバル名前空間に導入したくないと思います。 – Joald
グローバルネームスペースでmixinクラスを強制的に使用するにはどうすればよいですか?インライン化と 'enable_if()'の別の層を必要に応じて追加するだけです。 – user0042