3

私はDで線形代数ライブラリの多次元テンソルを実装しています.これは基本的に私が基本クラスのために目指していたものです:

class Tensor( T_scalar, T_dimensions ..., int T_storageOrder = StorageOrder.columnMajor )
{
}

このアイデアでは、ユーザーはテンプレート パラメーターを使用してテンソルの特性を定義でき、その結果、Eigen のように、コンパイル時にできるだけ多くのことを推測できます。残念ながら、コンパイラはその定義に満足しておらず、次のようなエラーを引き起こします。

Tensor(T_scalar,T_args...,int T_storageOrder = StorageOrder.columnMajor) template tuple parameter must be last one

この制限が設けられている理由はよくわかりませんが、最終的にハックと見なされることを行いました...基本的に、StorageOrderを列挙型として定義すると、テンプレートタプルパラメーターの最後の引数が一致するかどうかを確認できます列挙型からの値の、そしてそうであれば、それを使用してそのテンソルの StorageOrder の値を設定できます。それ以外の場合は、デフォルト値で設定します。

enum StorageOrder : int
{
  columnMajor = -1,
  rowMajor = -2
}



class Tensor( T_scalar, T_args ... )
{
private:

  alias TensorTraits!( T_scalar, T_args ) traits;
  alias traits.dimensions T_dimensions;
  alias traits.storageOrder T_storageOrder;
}



struct TensorTraits( T_scalar, T_args ... )
    if ( areTemplateParametersValid!( T_scalar, T_args )() )
{
  static immutable auto dimensions = mixin( extractDataFromTemplateTupleParameter.dimensions );
  static immutable int storageOrder = extractDataFromTemplateTupleParameter.storageOrder;


private:

  static auto extractDataFromTemplateTupleParameter()
  {
    Tuple!( string, "dimensions", int, "storageOrder" ) templateTupleParameterData;
    static if ( T_args[$ - 1] == StorageOrder.columnMajor || T_args[$ - 1] == StorageOrder.rowMajor )
    {
      alias TypeTuple!( T_args[0 .. $ - 1] ) dimensionsTuple;
      templateTupleParameterData.storageOrder = T_args[$ - 1];
    }
    else
    {
      alias TypeTuple!( T_args ) dimensionsTuple;
      templateTupleParameterData.storageOrder = StorageOrder.columnMajor;
    }

    static assert( dimensionsTuple.length > 0,
        "No dimensions have been defined." );

    foreach ( dimension; dimensionsTuple )
    {
      static assert( isIntegral!( typeof( dimension ) ),
        "Dimensions sizes needs to be defined as integrals." );

      static assert( dimension >= 0,
        "Dimensions sizes cannot be negative." );
    }

    templateTupleParameterData.dimensions = dimensionsTuple.stringof;
    return templateTupleParameterData;
  }
}


static bool areTemplateParametersValid( T_scalar, T_args ... )()
{
  static assert( isNumeric!( T_scalar ),
      "The 'T_scalar' template argument is not a numeric type." );

  static assert( T_args.length > 0,
      "No dimensions have been defined." );

  return true;
}

私は D を使い始めたばかりで、このハックについてよくわからないので、これが皆さんにとって良いと思われるかどうか、またはこれを処理するためのより良い方法があるかどうかを知りたいです。

4

2 に答える 2

1

あなたが言うように、それはハックであり、不要なハッキングは避けるべきです。

1 つの (明白な) 解決策は、ディメンションの前に格納順序を移動することですが、そのデフォルトのパラメーターを使用したいと思います。

これを回避するには、行と列の主要な特定のテンプレートを作成できます。

// Generic Tensor with storage order before dimensions.
class Tensor( T_scalar, int T_storageOrder, T_dimensions... )
{
}

template TensorRowOrder( T_scalar, T_dimensions... )
{
    alias Tensor( T_scalar, StorageOrder.rowMajor, T_dimensions ) TensorRowOrder;
}

template TensorColumnOrder( T_scalar, T_dimensions... )
{
    alias Tensor( T_scalar, StorageOrder.columnMajor, T_dimensions ) TensorColumnOrder;
}

その後、ユーザー コードで または をTensorRowOrder使用できます。または、ジェネリックが必要な場合にのみ使用できます。TensorColumnOrderTensorT_storageOrder

于 2012-09-01T17:20:28.223 に答える
0

参考までに、これは私がやったことです。

class Array( T_scalar, T_args ... )
{
private:

  alias ArrayTraits!( T_scalar, T_args ) traits;
  alias traits.isDynamic T_isDynamic;
  alias traits.shapeAtCompileTime T_shapeAtCompileTime;
  alias traits.sizeAtCompileTime T_sizeAtCompileTime;
  alias traits.storageOrder T_storageOrder;
  alias traits.dataType T_dataType;
}


struct ArrayTraits( T_scalar, T_args ... )
    if ( areTemplateParametersValid!( T_scalar, T_args )() )
{
private:

  static if ( hasFlag( Flags.storageOrder ) )
    alias T_args[0 .. $ - 1] shapeTuple;

  else
    alias T_args shapeTuple;


public:

  static immutable bool isDynamic = hasFlag( Flags.dynamic ) ? true : false;
  static immutable auto shapeAtCompileTime = getShapeAtCompileTime();
  static immutable size_t sizeAtCompileTime = getSizeAtCompileTime();
  static immutable StorageOrder storageOrder = hasFlag( Flags.storageOrder ) ?
      T_args[$ - 1] : defaultStorageOrder;

  static if ( hasFlag( Flags.dynamic ) == true )
    alias T_scalar[] dataType;

  else
    alias T_scalar[sizeAtCompileTime] dataType;


public:

  static auto getShapeAtCompileTime()
  {
    static if ( hasFlag( Flags.dynamic ) == true )
    {
      static assert( shapeTuple.length == 1,
          "The shape of a dynamic array needs to be defined at run-time." );

      size_t[1] shapeAtCompileTime = [Storage.dynamic];
      return shapeAtCompileTime;
    }
    else
    {
      static assert( shapeTuple.length > 0,
          "No dimensions have been defined." );

      size_t[shapeTuple.length] shapeAtCompileTime;
      foreach ( i, dimension; shapeTuple )
      {
        static assert( isIntegral!( typeof( dimension ) ),
            "Dimensions sizes for a static array needs to be defined as integrals." );

        static assert( dimension > 0,
            "Dimensions sizes for a static array cannot be null or negative." );

        shapeAtCompileTime[i] = dimension;
      }

      return shapeAtCompileTime;
    }
  }


  static size_t getSizeAtCompileTime()
  {
    if ( hasFlag( Flags.dynamic ) == true )
      return 0;

    size_t size = 1;
    foreach ( dimension; shapeAtCompileTime )
      size *= dimension;

    return size;
  }


private:

  /++ Parses the template tuple parameter to extract the different flags passed, if any. +/
  static int getFlags()
  {
    int flags = 0;
    if ( is( typeof( T_args[0] ) == Storage ) && T_args[0] == Storage.dynamic )
      flags |= Flags.dynamic;

    if ( is( typeof( T_args[$ - 1] ) == StorageOrder ) )
      flags |= Flags.storageOrder;

    return flags;
  }


  /++ Checks if the template tuple parameter contains a specific flag. +/
  static bool hasFlag( Flags flag )
  {
    return (getFlags() & flag) == 0 ? false : true;
  }


private:

  enum Flags : int
  {
    dynamic = 1 << 0,
    storageOrder = 1 << 1
  }
}


bool areTemplateParametersValid( T_scalar, T_args ... )()
{
  static assert( T_args.length > 0,
      "No dimensions have been defined." );

  return true;
}
于 2012-09-22T10:49:35.567 に答える