2017-11-28 4 views
0

テンプレートクラス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のときにダミー関数を追加すると、誰かがそれらの関数をコンパイルするコードを作ることになります。どうしたらいいですか?

+0

のようなものをあなたは_mixins_ではなく、[CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)を使用する必要がある場合。 – user0042

+0

私は書きましたが、Foo以外の名前をグローバル名前空間に導入したくないと思います。 – Joald

+0

グローバルネームスペースでmixinクラスを強制的に使用するにはどうすればよいですか?インライン化と 'enable_if()'の別の層を必要に応じて追加するだけです。 – user0042

答えて

3

Fooは余分なものがあり、それは部分的な特殊化、例えばFoo<Irrelevant, void>の部分を継承していますか?

は私が意味:

// with extra only 
template <typename Irrelevant, typename Extra> 
class Foo : public Foo<Irrelevant, void> 
{ 
    private: 
     Extra extra; 

     static_assert(is_good_v<Extra>); 

    public: 
     // to make visible the inherited constructor(s) 
     using Foo<Irrelevant, void>::Foo; 

     // to disable (?) a specific inherited constructor 
     // Foo(Irrelevant i) = delete; 

     //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;} 

     Extra getExtra() {return extra;} 
}; 

// common part, no extra 
template <typename Irrelevant> 
class Foo<Irrelevant, void> 
{ 
    public: 
     Foo(Irrelevant i) {/* irrelevant */} 
}; 
+0

それは本当にいいです、私はテンプレートの専門化が同じテンプレートの別の専門分野から継承することができたことを知らなかった、ありがとう! – Joald

+0

@Joald - そうですか:私は数日前にそれを発見しましたが、今は広範囲に使用しています。 – max66

関連する問題