3

STM32 のハードウェア タイマーを使用して、多数の光学式エンコーダと接続しています。ハードウェア タイマーとやり取りするための便利なインターフェイスを提供する、テンプレート化されたクラスを作成したいと考えています。タイマー レジスタはメモリ マップされており、そのアドレスは、デバイスのデータシートと一致するメーカー提供のヘッダーで定義されています。テンプレート パラメータは、事実上、タイマー ペリフェラルのベース メモリ アドレスになります。以下は、私が現在やろうとしていることの最小限の実例です。

#include <cstdint>

// Effectively supplied by chip manufacturer headers
struct timer_peripheral {
  volatile uint32_t count;
  // ... lots of other registers ...
};
// Also supplied by chip manufacturer headers
#define TIM1 ((timer_peripheral *) 0x40000000)
#define TIM2 ((timer_peripheral *) 0x40000400)
// My templated class
template <timer_peripheral * Timer>
class OpticalEncoderCounter {
  OpticalEncoderCounter();
};

template <timer_peripheral * Timer>
OpticalEncoderCounter<Timer>::OpticalEncoderCounter()
{
}

int main()
{
  // option 1
  OpticalEncoderCounter<TIM1> encoder0;

  // option 2
  timer_peripheral * t = TIM2;
  OpticalEncoderCounter<t> encoder1;
}

ただし、コンパイルすると、g++-4.7.2 -std=c++11 で次のエラーが発生します。

エラー| テンプレート引数 '1073742848u' を 'timer_peripheral*' に変換できませんでした</p>

エラー| 「t」は変数のアドレスではなく変数であるため、「t」は有効なテンプレート引数ではありません

非型テンプレート パラメーターについて読んだ後でも、問題を解決する方法と、自分が考えている方法でテンプレートを使用できるかどうかはまだわかりません。オプション 1 で static_cast と reinterpret_cast を試しましたが、違いはないようです。

4

3 に答える 3

1

短縮版

テンプレートの非型引数は定数式でなければなりません。((timer_peripheral *) 0x40000000)にはポインタ型へのが含まれているreinterpret_castため、定数式では使用できません。


C++03

[temp.arg.nontype]/1

非型、非テンプレートのテンプレート パラメータのテンプレート引数は、次のいずれかになります。

  • 整数型または列挙型の整数定数式。また
  • [...]
  • 関数テンプレートと関数テンプレート ID を含むが、非静的クラス メンバを除く、外部リンケージを持つオブジェクトまたは関数のアドレス。名前が関数または配列を参照する& id-expression場合&、または対応するテンプレート パラメータ参照です。また
  • [...]

したがって、整数定数式を使用する必要があります。

[expr.const]/1

整数定数式には、リテラル (2.13)、定数式 (8.5) で初期化された整数型または列挙型の列挙子、const 変数または静的データ メンバー、整数型または列挙型の非型テンプレート パラメーター、および sizeof 式のみを含めることができます。[...]整数型または列挙型への型変換のみを使用できます。

((timer_peripheral *) 0x40000000)にはポインター型へのキャストが含まれているため、整数定数式には表示できません。


C++11

[temp.arg.nontype]/1

非型、非テンプレートのテンプレート パラメータのテンプレート引数は、次のいずれかになります。

  • 整数型または列挙型の非型テンプレート パラメーターの場合、テンプレート パラメーターの型の変換された定数式 (5.19)。また
  • [...]
  • 関数テンプレートと関数テンプレート ID を含むが非静的クラス メンバーを除く、静的ストレージ期間と外部または内部リンケージを持つオブジェクト、または外部または内部リンケージを持つ関数のアドレスを指定する定数式 (5.19)ただし& id-expression&名前が関数または配列を参照する場合は省略でき、対応するテンプレート パラメータが参照の場合は省略されます。また
  • [...]

「アドレスを設計する…」という定数式は使えませんが、変換された定数式を使えないでしょうか?

[expr.const]/2

条件式は、次のいずれかを含まない限り、コア定数式です [...]

  • [...]
  • reinterpret_cast (5.2.10);
  • [...]

いいえ。ありえない。


回避策

関数テンプレートを使用してポインターを返します。

#include <cstdint>

// Effectively supplied by chip manufacturer headers
struct timer_peripheral {
    volatile uint32_t count;
    // ... lots of other registers ...
};

#define TIM1 ((timer_peripheral *) 0x40000000)
#define TIM2 ((timer_peripheral *) 0x40000400)

enum TIMS { tim1, tim2 };

template < TIMS tim >
inline timer_peripheral* get_timer_address()
{
    static_assert(tim && false, "unknown timer identifier");
    return nullptr;
}
  template <>
  inline timer_peripheral* get_timer_address < tim1 >()
  {
      return TIM1;
  }
  template <>
  inline timer_peripheral* get_timer_address < tim2 >()
  {
      return TIM2;
  }

// My templated class
template < TIMS tim >
class OpticalEncoderCounter {
    static timer_peripheral* get() { return get_timer_address<tim>(); }

public:
    OpticalEncoderCounter();
};

template < TIMS tim >
OpticalEncoderCounter<tim>::OpticalEncoderCounter()
{
}

int main()
{
    OpticalEncoderCounter<tim1> encoder0;
}
于 2013-05-15T22:39:43.613 に答える
0

ポインター演算を使用して、ポインターを定数整数に変換します。

// My templated class


#define TIM_BASE TIM1

const int TIM1_OFFSET = TIM1 - TIM_BASE;

template <size_t timerOffset>
class OpticalEncoderCounter {
public:
  OpticalEncoderCounter();

  timer_peripheral * getTimer() { return  TIM_BASE + timerOffset;}

};

template <size_t timerOffset>
OpticalEncoderCounter<timerOffset>::OpticalEncoderCounter()
{

}


int main()
{

  OpticalEncoderCounter<TIM1_OFFSET> encoder0;

}
于 2013-05-15T23:27:02.953 に答える