3

次のようコードがあります。

// filexd.h
function() {
  // nDim is a compile time constant
  #if DIMENSIONS == 2
    static const int a[nDim] = {1,0};
  #elif DIMENSIONS == 3
    static const int a[nDim] = {2,0,1};
  #else
    #error "Unknown # of dimensions"
  #end
  // do stuff with a...
}

このファイルは、マクロ DIMENSIONS を再定義する他のユーザーによってインクルードされます。私がしたいのは次のようなものです:

static const int a[nDim] = (nDim == 2) ? {0,1} : {1,0,2};

どちらの場合もコードの 99% が同一であるため、関数テンプレートの特殊化またはタグ ディスパッチを使用したくありません。すでに持っていたのと同じ関数構成と、変数 a のローカル セマンティクスを保持したいと思います。質問は次のとおりです。

この状況でマクロを使用しないようにするにはどうすればよいですか?

ここで C++1y テンプレート変数を使用できますか? 以下は機能しますか?

// filexd.h
function() {

  // The general case should fail somehow, maybe displaying a nice error message.
  template<int nDim> constexpr int stencil[nDim] = throw();
  // And then define the variable for both cases:
  template<> constexpr int stencil<2>[2] = {1, 0};  
  template<> constexpr int stencil<3>[3] = {2, 0, 1};

  static const stencil<nDim> a;
  for(int i = 0; i < nDim; ++i) {
    /// do stuff with a[i]
  }
}

関数自体の内部で特殊化されたステンシル テンプレート変数を宣言できますか?

4

3 に答える 3

5
template<size_t N>
void the_common_work(const int(&arr)[N])
{
    for (size_t i=0; i<N; ++i)
      /// do stuff with arr[i]
}

void function()
{        
    if (nDim == 2)
    {
        int a[2] = {1,0};
        the_common_work(a);
    }
    else if (nDim == 3)
    {
        int a[3] = {2,0,1};
        the_common_work(a);
    }
}

必要に応じてそこに投げstatic_assertます。

実際、ここではテンプレート関数を使用する必要さえありません。C でもこれを行うことができます。

void the_common_work(const int * arr)
{
    for (size_t i=0; i<nDim; ++i)
        /// do stuff with arr[i]
}

1つの機能での代替:

void function()
{
    const int two[] = {1,0};
    const int three[] = {2,0,1};
    const int *arr;
    if (nDim == 2)
        arr = two;
    else if (nDim == 3)
        arr = three;
    else
    {
        throw something;
    }
    for(int i = 0; i < nDim; ++i) {
        /// do stuff with arr[i]
    }
}
于 2013-05-12T10:51:04.517 に答える
5

この場合はおそらくやり過ぎですが、変換演算子はこれを行うための優れた方法を提供できます。

#include <array>
template<int i>
void f() {
    struct init {
        constexpr operator std::array<int, 2>() { return { { 1, 0 } }; }
        constexpr operator std::array<int, 3>() { return { { 2, 0, 1 } }; }
    };
    constexpr std::array<int, i> a = init{};
}

initラムダを使用して名前が関数の名前空間に漏れるのを防ぐことができますが、次のようになりconstexprます。

#include <array>
template<int i>
void f() {
    const std::array<int, i> a = [](){
        struct init {
            operator std::array<int, 2>() { return { { 1, 0 } }; }
            operator std::array<int, 3>() { return { { 2, 0, 1 } }; }
        };
        return init{};
    }();
}
于 2013-05-16T07:58:20.170 に答える