7

テンプレート クラスで一部のメンバー関数を非表示にすることは可能ですか? 次のようなものがあるとしましょう。

template <class T>
class Increment
{
public:
    void init(T initValue)
    {
         mValue = initValue;
    }  

    T increment()
    {
        ++mValue;
    }

    T increment(T delta)
    {
        mValue += delta;
    }
private:
    T mValue;
};

目的は、特定のケースでは increment() 関数のみが表示され、他のケースではインクリメント(T) メンバー関数のみが表示されるように、このクラスを使用することです。そのために、SFINAE で何かを考えることができます。

class MultipleIncrement
{
    typedef int MultipleIncrement_t;
};

class SingleIncrement
{
    typedef int SingleIncrement_t;
};

template <class T, class Q>
class Increment
{
public:
    void init(T initValue)
    {
        mValue = initValue;
    }

    T increment(typename Q::SingleIncrement_t = 0)
    {
        ++mValue;
    }

    T increment(T delta, typename Q::MultipleIncrement_t = 0)
    {
        mValue += delta;
    }
private:
    T mValue;
}

次に、たとえば次のようにテンプレートを使用します。

Increment<long, MultipleIncrement>

ただし、コンパイラはこれを許可していません。これが実現可能な他の方法はありますか?メンバー関数が実際にコンストラクターである場合にも機能しますか?

4

3 に答える 3

3

この場合、テンプレートの特殊化を使用することをお勧めします。このようなものはあなたを助けますか?

struct SingleIncrement;
struct MultipleIncrement;

template <
    class T, 
    class Policy = SingleIncrement // default template param
>
class Increment
{
    T mValue;
public:
    Increment(T initValue)
    :   mValue(initValue)
    {}

    T increment()
    {
        ++mValue;
    }
};

// template specialization for MultipleIncrement
template <class T>
class Increment<T,MultipleIncrement>
{
    T mValue;
public:
    Increment(T initValue)
    :   mValue(initValue)
    {}

    T increment(T delta)
    {
        mValue += delta;
    }
};
于 2011-04-20T19:23:17.303 に答える
1

テンプレートの専門化は良いです。継承のほうがよさそうです。継承された基本クラスでのテンプレート化を検討しましたか? (または、これは現在、偽物と見なされていますか?)

#define SHOW(X)  cout << # X " = " << (X) << endl

template <class T>
class A
{
public:
  void foo(T t) {SHOW(t); }
};

template <class T, class BASE>
class B : public BASE
{
public:
  void bar(T t) {SHOW(t); }
};

int
main()
{
  B<int,A<int> > b;
  b.foo(1);
  b.bar(2);
}
于 2011-04-20T19:44:52.427 に答える
1

これを実現する方法の MWE は次のとおりです。

#include <iostream>

using namespace std;

struct multi;
struct single;

template<class T, class Q>
struct dummy {
  dummy(T value) : m_value(value) { }

  // using enable_if_t in template argument
  template<class _Q = Q, enable_if_t<is_same<_Q, single>::value && is_same<_Q, Q>::value, int> = 1>
  T increment() { return ++m_value; }

  // using enable_if_t in method return type
  template<class _Q = Q>
  enable_if_t<is_same<_Q, multi>::value && is_same<_Q, Q>::value, T>
  //enable_if_t<is_same<_Q, multi>::value, T> // (*)
  increment(T delta) { return (m_value += delta); }

  T m_value;
};

int main() {
  dummy<double, multi> m(47.10);
  //cout << m.increment() << endl; // error as expected
  cout << m.increment(.01) << endl;

  dummy<int, single> s(41);
  cout << s.increment() << endl;
  cout << s.increment<single>() << endl;
  //cout << s.increment(1) << endl; // error as expected
  //cout << s.increment<multi>(1) << endl; // not an error when using (*)
}

出力

これを使用c++ (Debian 6.2.1-5) 6.2.1 20161124すると、次の結果が得られます。

47.11
42
43

推敲

SFINAE を機能させるには、メソッドをテンプレート化する必要があります。次のようなものは使用できません

std::enable_if_t<std::is_same<_Q, multiple_increment>::value, T> increment() ...

メソッド テンプレート パラメーターを置換するときに失敗するのではなく、テンプレートをインスタンス化するときに失敗するためです。dummy<T, single_increment>

さらに、メソッド テンプレート パラメーターを実際に提供しなくても、ユーザーがメソッドを使用できるようにしたいと考えています。そのため、メソッド テンプレート パラメータの_Qデフォルトを にしQます。

最後に、メソッド テンプレート パラメーターを提供する場合でも、不要なメソッドを使用するときにコンパイラ エラーを実際に発生させるには、enable_if_tメソッド テンプレート パラメーター_Qが実際にそれぞれのクラス テンプレート パラメーターと同じ型である場合にのみメソッドを使用しますQ

于 2016-12-08T21:22:22.823 に答える