2017-01-08 1 views
1

使用しているプログラムが特定のテンプレート引数に対して非型のテンプレートクラスメソッドを呼び出すと、コンパイラエラーが発生します。特定の型以外の値に対してテンプレートサブクラスメソッドをインスタンス化しようとすると、コンパイラエラーが発生する

Super.h:

class Super { 
    protected: 
     Super() {} 
    public: 
     virtual void doSomething(); 
     void doSomethingElse(); 
}; 

Super.cpp:

typedef SubWithTemplate<1> SubWithTemplate1; 
typedef SubWithTemplate<2> SubWithTemplate2; 

SubWithTemplate1 &subWithTemplate1 = SubWithTemplate1::instance; 
SubWithTemplate2 &subWithTemplate2 = SubWithTemplate2::instance; 

subWithTemplate1.doSomething(); // Should compile OK 
subWithTemplate1.doSomethingElse(); // Should compile OK 
subWithTemplate2.doSomething(); // Should NOT compile OK 
subWithTemplate2.doSomethingElse(); // Should compile OK 

私の出発点は、2次のクラスである

void Super::doSomething() {} 
void Super::doSomethingElse() {} 

SubWithTemplate.h:

template<int SUBNUMBER> 
class SubWithTemplate : public Super { 

    public: 
     static SubWithTemplate<SUBNUMBER> instance; 
     void doSomething() { 
      // Do something 
     }; 

    private: 
     SubWithTemplate() : Super() {} 
}; 

template<int SUBNUMBER> 
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance; 

私はBoostやmplにあまり流暢ではありませんが、BOOST_MPL_ASSERTが私にいくつかの成功をもたらしてくれるというあいまいな気持ちがあります。しかし、私はその根幹を理解できません。それはすべてのサブクラスで同じインスタンス化する必要がありますよう、

... 
void doSomething() { 
    BOOST_MPL_ASSERT_MSG(<some test on SUBNUMBER being different from 2 and 7 and less than 25>, <what here?>, <what here?>) 
}; 
... 

私はスーパーがテンプレート化されないようにする:

SubWithTemplate.h:

は、私のようなものを試してみました。

doSomethingでバーチャルを使用することを避けることができれば、さらに優れています。

私の専門家が私を助けることができれば、とても感謝しています。

+0

あなたは(私は疑っている)これを達成することができますと仮定しますが、以来、 'doSomethingの()'あなたがタイプのオブジェクトに 'スーパー*'型のポインタを経由して呼び出されることを防ぐことができますどのように、仮想であります ' SubWithTemplate <2> '?その呼び出しは、実行時にのみ検出可能です! –

+0

私は仮想を取り除き、メソッドを保護された状態にすることで問題が解決されると思います。しかし、SubWithTemplate <2>インスタンスは、そのprotected superメソッドを呼び出すことができます。私の場合は、スーパーユーザーがライブラリユーザーの継承を意図していないため、SubWithTemplateのみが公開されているため、これは問題ありません。 –

答えて

3

C++ 11を使用できるのであれば、SFINAE経由でdoSomething()を無効にするのはどうですか?次の例では

このソリューションはギヨームRacicot(ありがとう!)で指摘したようにdoSomething()SUBNUMBER ---

#include <type_traits> class Super { protected: Super() {} void doSomething() {} public: void doSomethingElse() {} }; template <int SUBNUMBER> class SubWithTemplate : public Super { public: static SubWithTemplate<SUBNUMBER> instance; template <int I = SUBNUMBER> typename std::enable_if<I!=2>::type doSomething() { Super::doSomething(); } private: SubWithTemplate() : Super() {} }; template<int SUBNUMBER> SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance; typedef SubWithTemplate<1> SubWithTemplate1; typedef SubWithTemplate<2> SubWithTemplate2; int main() { SubWithTemplate1 &subWithTemplate1 = SubWithTemplate1::instance; SubWithTemplate2 &subWithTemplate2 = SubWithTemplate2::instance; subWithTemplate1.doSomething(); // OK subWithTemplate1.doSomethingElse(); // OK //subWithTemplate2.doSomething(); // compilation error subWithTemplate2.doSomethingElse(); // OK } 

2を除くEDIT ---

のすべての値に対して有効になっていますテンプレート値を説明することを回避することができます(I = SUBNUMBERはデフォルトです)。

(OPで尋ねたとして)もしそうなら

subWithTemplate2.doSomething(); 

は問題なくコンパイル

subWithTemplate2.doSomething<1>(); 

、コンパイルエラーを与えます。

これを避けるには、いくつか解決策を提案することができます。

(1)関数の本体にstatic_assert()を追加して、I == SUBNUMBERを課すことができます。何かのように

template <int I = SUBNUMBER> 
    typename std::enable_if<I!=2>::type doSomething() 
    { 
     static_assert(I == SUBNUMBER, "I != SUBNUMBER; this in wrong"); 
     Super::doSomething(); 
    } 

(2)Guillaume Racicot(もう一度ありがとう!)、std::enable_if<>テストでI == SUBNUMBERを統合できます。何かのように

template <int I = SUBNUMBER> 
    typename std::enable_if<(I!=2) && (I == SUBNUMBER)>::type 
     doSomething() 
    { Super::doSomething(); } 

私はもう少しエレガントですが、私は専門家ではなく、私にとっては味の問題です。

--- EDIT 2 ---

枝番が与えられた区間内にある場合を除き、どのように私は、インスタンス化されることからSubWithTemplateクラスを防ぐことができますか?

フルクラスを防ぐために暑いですか? doSomething()の方法だけでなく、

私の頭に浮かぶ最初の方法は、static_alert()の使用です。

たとえば、[5,10 [(5を含む、10を除いた)]の範囲の許可のみをSUBNUMBERにしたい場合は、次のようにコンストラクタを記述できます。

SubWithTemplate() : Super() 
{ static_assert((SUBNUMBER >= 5) && (SUBNUMBER < 10), "error message"); } 

しかし、私は他の方法があると思います。

--- EDIT 3 ---

枝番号が所定間隔内でなければ、インスタンス化されることSubWithTemplateクラスを防止する別の方法。

C++ 98でも動作する方法。

デフォルトの特殊化とテンプレートのデフォルト値に基づいています。

class Super 
{ 
    protected: 
     Super() {} 
     void doSomething() {} 

    public: 
     void doSomethingElse() {} 
}; 

template<bool b> struct boolWrapper {}; 

template <int I, bool = (I >= 0) && (I <= 20)> 
struct rangeLimit; 

template <int I> 
struct rangeLimit<I, true> 
{ }; 

template <int SUBNUMBER> 
class SubWithTemplate : public Super, public rangeLimit<SUBNUMBER> 
{ 
    public: 
     static SubWithTemplate<SUBNUMBER> instance; 

     void doSomething() 
     { Super::doSomething(); } 

    private: 
     SubWithTemplate() : Super() {} 
}; 

template<int SUBNUMBER> 
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance; 

typedef SubWithTemplate<1> SubWithTemplate1; 
typedef SubWithTemplate<2> SubWithTemplate2; 
typedef SubWithTemplate<20> SubWithTemplate20; 
//typedef SubWithTemplate<21> SubWithTemplate21; compilation error 

int main() 
{ 
} 
+0

enable_ifの条件を 'I!= 2 && I == SUBNUMBER'に変更して、関数が' I'値を上書きしないようにしてください。 –

+0

このソリューションをお寄せいただきありがとうございます。それは私のためにうまくいく、私の主な要件が満たされています。しかし、あなたの中にはもっと美しいレシピが見つかる人もいれば、大歓迎です。 @ max66、あなたは "...素晴らしい解決策ではありません..."と書いています。もっと具体的に考えていますか? –

+0

@GuillaumeRacicot - あなたが正しいです。ありがとう。 – max66

関連する問題