web-dev-qa-db-ja.com

コンパイル時にゼロのシーケンスを生成する

次の問題があります。

template< size_t... N_i >
class A
{
  public:

    // ...

    void foo()
    {
      bar( /* 0,...,0 <- sizeof...(N_i) many */);
    }
};

関数barを呼び出してsizeof...(N_i)多くの引数をすべてゼロにしたいです。たとえば、bar(0,0,0)の場合はsizeof...(N_i) == 3です。これはどのように実装できますか?

38
abraham_hilbert
bar(((void)N_i, 0)...);

コンマ演算子はN_iを破棄し、右側のオペランドの値(0)のみを生成します。キャストは、N_iが破棄されることに関する警告を防ぐためのものです。

60
Columbo

間違いなく興味深い answer by @Columbo にもかかわらず、constexprのテンプレート変数に基づく別の実行可能なソリューションを提案したいと思います。

 #include <cstddef> 

 template<std::size_t, std::size_t V>
 constexpr std::size_t repeat_value = V;

 template<std::size_t... N_i>
 class A {
     template<typename... Args>
     void bar(Args&&...) { }

 public:   
      void foo() {
           // repeat N_i times value 0
           bar(repeat_value<N_i, 0>...);
      }
 };

 int main() {
      A<0, 1, 2, 3, 4> a;
      a.foo();
 }

コンパイル時のパフォーマンスが悪いとしても、少なくとも読みやすいと思います。


次のように簡単に一般化できます。

template<std::size_t, typename T, T V>
constexpr T repeat_value = V;

特定のケースでの呼び出しは次のとおりです。

bar(repeat_value<N_i, int, 0>...);
9
skypjack

テンプレートを使用して、同様のものをシミュレートすることもできます。これは非常に基本的なソリューションであり、0のリストを作成するだけですが、必要に応じて他のシーケンスを生成するように拡張することもできます。

template <size_t Unused>
struct Wrap {
  static constexpr size_t value = 0;
};

template <size_t... N_i>
class A {
public:
    void foo() {
        bar(Wrap<N_i>::value...);
    }
};

これは、N_i引数と同じサイズのゼロのリストに展開されます。確かに、インターフェースは少し異なります。

バーが受け取る要素の値を示す完全な例については、ここを参照してください。 ライブの例

2
RobClucas