30

使用するインターフェイスを公開するライブラリを使用しています。このライブラリの機能の1つは次のようなものです:

template <int a>
void modify(){}

パラメータを1から10に変更する必要があります。つまり、1から10modifyのテンプレート引数を使用して呼び出します。そのために、このコードを作成しました(コードの基本バージョン、実際のコードははるかに大きい)。

for(int i=0; i<10; i++){
    modify<i>();
}

コンパイル時に次のエラーが発生します

error: 'i' cannot appear in constant-expression

インターネット上のいくつかのリンクを調べた後、コンパイル時に評価されないテンプレート引数として値を渡すことができないことがわかりました。私の質問は次のとおりです。1。コンパイラiがコンパイル時に評価できないのはなぜですか。2. APIインターフェースを変更せずに、達成しようとしている目的を達成するために他に何かありますか?


もう一つやりたいことがあります。VARが機能計算の出力であるmodifyをmodifyとして呼び出します。どうやってやるの?

4

6 に答える 6

37

コンパイル時のi (定数ではない)の値は? ループを実行しないと答えようがありません。しかし、実行は「コンパイル」ではありません。答えがないため、コンパイラはそれを行うことができません。

テンプレートは実行されるアルゴリズムではなく、コードを生成するために展開されるマクロです。あなたができることは、次のように、再帰による反復を実装するための特殊化に依存することです:

#include <iostream>

template<int i>
void modify()
{ std::cout << "modify<"<<i<<">"<< std::endl; }

template<int x, int to>
struct static_for
{
    void operator()() 
    {  modify<x>();  static_for<x+1,to>()(); }
};

template<int to>
struct static_for<to,to>
{
    void operator()() 
    {}
};


int main()
{
    static_for<0,10>()();
}

これを行うことで、実際には...という名前の 10 個の関数をインスタンス化し 、それぞれmodify<0>...modify<9>によって呼び出されることに注意してください。static_for<0,10>::operator()static_for<9,10>::operator()

2 つの同一の値を取る特殊化からインスタンス化されるため、反復は終了static_for<10,10>しますが、何もしません。

于 2012-06-18T11:25:05.807 に答える
3
  1. 「なぜコンパイラiはコンパイル時に評価できないのですか?」

    それはテンプレートの目的を無効にします。テンプレートは、ソース コードがいくつかのケースで同じように見えるが、コンパイラが生成する必要がある命令が毎回異なる場合のために用意されています。

  2. 「API インターフェイスを変更せずに、私が達成しようとしている目的を達成する方法は他にありますか?」

    はい、Boost.MPLを見てください。

    ただし、ここでの正しい答えは、API を変更したいということだと思います。関数の内部に依存しmodifyます。テンプレートはヘッダーで定義する必要があるため、ソースがあることは知っています。iしたがって、コンパイル時に知る必要がある理由を見てください。そうでない場合は、パラメーターを使用して通常の関数に置き換える (または下位互換性を維持する必要がある場合は補完する) のが最善です。

于 2012-06-18T11:25:47.143 に答える
3

Boost.MPLを使用して回答を求めたので:

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>

#include <iostream>

template <int N>
void modify()
{
    std::cout << N << '\n';
}

// You need to wrap your function template in a non-template functor
struct modify_t
{
    template <typename N>
    void operator()(N)
    {
        modify<N::value>();
    }
};

int main()
{
    namespace mpl = boost::mpl;

    mpl::for_each< mpl::range_c<int,0,10> >( modify_t() ); // prints 0 to 9
}
于 2012-06-18T12:23:17.057 に答える
1

structまたはBoostを使用せずに、次のこともできます。

#include <iostream>
#include <utility>

template <int a>
void modify()
{
    std::cout<<a<<",";
}

template<int i,size_t... t>
constexpr inline void CT_for_impl(std::integer_sequence<size_t,t...>)
{
    bool kai[]= { (modify<i+t>(), false)...};
}

template<int i,int n>
constexpr inline void CT_for()
{
    CT_for_impl<i>(std::make_index_sequence<n-i+1>());
}

int main()
{
    CT_for<-5,5>();
    return 0;
}
于 2016-09-07T23:09:57.937 に答える
1

実行時にインデックスで関数を呼び出したいが、API を変更できない場合は、型消去を検討できます。

std::vector<std::function<void(int)> > func;
func.push_back(modify<1>);
func.push_back(modify<2>);
//... and so on ...
func.push_back(modify<10>);

for(int i=0; i<10; ++i)
{
    func[i]();  //calls modify<i+1>();
}

言及するいくつかのポイント:

  • これはテンプレートの主な目的ではありませんが、静的ライブラリをランタイムの世界に持ち込む方法です。これの基本的な要件は、同種の型で動作することです (--ifmodify<7>()が返すと、たとえば、std::string全体のアプローチが壊れます)。
  • 型消去を使用する以前のソリューションにはオーバーヘッドがあります。関数ポインターを使用すると高速になる可能性がありますが、コンパイル時に関数を呼び出すよりも常に遅くなります。
  • push_backs を別の反復的な静的関数にラップして、手動呼び出しを回避することもできます (また、ラップする必要があります) 。
于 2017-11-01T06:50:07.680 に答える