41

テンプレート パラメーターの 1 つに数値定数を指定して、C++ テンプレート クラスの部分的な特殊化を定義する簡単な方法はありますか? 特定の種類のテンプレートの組み合わせ専用の特別なコンストラクターを作成しようとしています:

template <typename A, size_t B> class Example
{
    public:
        Example() { };

        A value[B];
};

template <typename A, 2> class Example
{
    public:
        Example(b1, b2) { value[0] = b1; value[1] = b2; };
};

Expected identifier before numeric constantこの例はコンパイルされず、2 番目の定義でエラーが返されます。

ここや他の場所で多くの例を見てきましたが、ほとんどは定数ではなく型の特殊化を中心に展開しているようです。

編集:

条件付きで使用されるコンストラクターを作成する方法を探しています。機能的には次のようになります。

template <typename A, size_t B> class Example
{
    public:
        // Default constructor
        Example() { };

        // Specialized constructor for two values
        Example<A,2>(A b1, A b2) { value[0] = b1; value[1] = b2; };

        A foo() {
          A r;

          for (size_t i = 0; i < b; ++b)
            r += value[i];

          return r;
        }

        // Hypothetical specialized implementation
        A foo<A, 2>() {
          return value[0] + value[1];
        }

        A value[B];
};
4

6 に答える 6

21

特殊化を正しい場所に配置する必要があります。

template <typename A> class Example<A,2>

サブクラスを作成する場合:

template <typename A> class ExampleSpecialization : public Example<A,2>

typedef を特殊化するための動作は、整数パラメーターを特殊化するための動作に似ています。

于 2011-01-30T02:48:19.830 に答える
10

私はこれがうまくいくかもしれないと思います:

#include <iostream>

template <typename A, size_t B>
class Example {
public:
    Example()
    {
        Construct<B>(identity<A, B>());
    }

    A foo()
    {
        return foo<B>(identity<A, B>());
    }

private:
    template <typename A, size_t B>
    struct identity {};

    template <size_t B>
    void Construct(identity<A, B> id)
    {
        for (size_t i = 0; i < B; ++i)
        {
            value[i] = 0;
        }
        std::cout << "default constructor\n";
    }

    template <size_t B>
    void Construct(identity<A, 2> id)
    {
        value[0] = 0;
        value[1] = 0;
        std::cout << "special constructor\n";
    }

    template <size_t B>
    A foo(identity<A, B> id)
    {
        A r = 0;
        for (size_t i = 0; i < B; ++i)
        {
            r += value[i];
        }
        std::cout << "default foo\n";
        return r;
    }

    template <size_t B>
    A foo(identity<A, 2> id)
    {
        std::cout << "special foo\n";
        return value[0] + value[1];
    }

    A value[B];
};

int main()
{
    Example<int, 2> example; // change the 2 to see the difference
    int n = example.foo();
    std::cin.get();
    return 0;
}

申し訳ありませんが、テストプロジェクトからコピーして貼り付けました。ある意味では実際には「特殊化」ではなく、特殊化された関数へのオーバーロードを呼び出すだけです。これがあなたが望むものであるかどうかはわかりませんが、これはあまりエレガントではありません。

于 2011-01-30T03:25:15.813 に答える
5

メモリが役立つ場合は、次のようになります。

template <typename A, size_t B> class Example
{
    public:
        Example() { };

        A value[B];
};

template <typename A> class Example<A, 2>
{
    public:
        Example(A b1, A b2) { value[0] = b1; value[1] = b2; };
};

ただし、これはそのままではまったく許容できるとは思いません。特殊化されたバージョンでは、b1および/またはのタイプを定義するものは何もありません。b2

編集 [編集された質問に基づく]: はい、テンプレートの特殊化は、特殊化されたベースに実際には関連しない新しい型を生成します。特に、この 2 つは実装を共有していません。非型パラメーターの値に応じて、2 つの異なる ctor のいずれかを使用する単一の型を (クラス テンプレートを特殊化することによって) 生成することはできません。

于 2011-01-30T02:48:01.313 に答える
3

次のようなことを試すことができます:

template<size_t s>
struct SizeTToType { static const size_t value = s; };

template<bool> struct StaticAssertStruct;
template<> struct StaticAssertStruct<true> {};
#define STATIC_ASSERT(val, msg) { StaticAssertStruct<((val) != 0)> ERROR_##msg; (void)ERROR_##msg;}

template <typename A, size_t B> 
class Example
{
    public:
        Example() { };
        Example(A b1){ value[0] = b1; }
        Example(A b1, A b2) { 
                STATIC_ASSERT(B >= 2, B_must_me_ge_2); 
                value[0] = b1; value[1] = b2;
        } 
        A foo() { return in_foo(SizeTToType<B>()); }
    protected:
        template<size_t C>
        A in_foo(SizeTToType<C>) {
                cout << "univ" << endl;
                A r;
                for (size_t i = 0; i < B; ++i)
                r += value[i];
                return r;
        }
        A in_foo(SizeTToType<2>){
                cout << "spec" << endl;
                return value[0] + value[1];
        }
        A value[B];
};

http://www.ideone.com/wDcL7での作業例

テンプレートでは、メソッドを使用していない場合、コンパイルされたコードには存在しません。そのため、特殊なクラスでは使用できない ctor のために、このソリューションで実行可能ファイルを大きくするべきではありませExample<int, 1>ん(たとえば、ctor を使用しないでくださいExample(A b1, A b2))。

于 2011-01-30T05:12:34.280 に答える
2

スペシャライゼーションのいくつかのメソッド/コンストラクターをオーバーライドするだけでよい場合は、すべてのExampleテンプレートに共通の実装を保持するジェネリック基本クラスを検討して、思いついたすべてのスペシャライゼーションでそれを書き直す必要がないようにします。 。

例えば:

template < typename A, size_t B >
class ExampleGeneric {
public:

  // generic implementation of foo inherited by all Example<A,B> classes
  void foo() {
    A r;

    for (size_t i = 0; i < B; ++i)
      r += value[i];

    return r;
    }

  // generic implementation of bar inherited by all Example<A,B> classes
  void bar() {
    A r;

    for (size_t i = 0; i < B; ++i)
      r *= value[i];

    return r;
    }

  A values[B];
  };

template < typename A, size_t B >
class Example : public ExampleGeneric<A,B> {
public:
  //default to generic implementation in the general case by not overriding anything
  };

//*** specialization for 2
template < typename A >
class Example<A,2> : public ExampleGeneric<A,2>{
public:

  // has to be provided if you still want default construction
  Example() {
    }

  //extra constructor for 2 parameters
  Example( A a1, A a2 ) {
    values[0] = a1;
    values[1] = a2;
    }

  // specialization of foo
  void foo() {
    return values[0] + values[1];
    }

  // don't override bar to keep generic version
  };
于 2011-01-30T04:57:22.557 に答える
0
#include <iostream>

using namespace std;


template<typename _T, size_t S>
class myclass {
    _T elem[S];
public:
    myclass() {
        for (int i = 0; i < S; i++) {
            elem[i] = i;
        }
    }
    void Print() {
        for (int i = 0; i < S; i++) {
            cout << "elem[" << i << "] = " << elem[i] << endl;
        }
    }
};


int main(int argc, char **argv)
{
    myclass < int, 10 > nums;
    nums.Print();
    myclass < int, 22 > nums1;
    nums1.Print();
}

それは私のLinuxマシンで動作しました

g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-48) Copyright (C) 2006 Free Software Foundation, Inc. これはフリー ソフトウェアです。条件のコピーについてはソースを参照してください。保証はありません。商品性や特定の目的への適合性のためでさえありません。

于 2012-05-30T22:00:34.173 に答える