1

私が作成したライブラリに含まれている次のコードを考えてみましょう。

#include <complex>

std::complex<double> besselJ(int order, std::complex<double> z)
{
    // Function call
}

std::complex<double> besselH1(int order, std::complex<double> z)
{
   // Function call
}

両方の関数のシグネチャが同じであることに注意してください。besselJここで、 に作用する場合でも に作用する場合でもまったく同じことを行う 3 番目の関数を書きたいと思いますbesselH1。私は次のことを試しました

template<std::complex<double> (*T)(int, std::complex<double>)>
std::complex<double> diffBessel(int order, std::complex<double> z)
{
    return T(order-1, z)-T(order+1,z);
}

メンバー関数が構文を使用しようとするとdiffbessel<besselJ>(int, std::complex<double>、GCC はそれを訴えますthe value of 'besselJ' is not usable in a constant expression説明については、この回答を参照してください。

besselJ上記のテンプレート化されたコードが、ラッピングやsbesselH1に頼らずに機能する場合に行うようなことを行う方法はありますか? struct構造体は不要な複雑さを追加すると思います。

更新: @ashepler が提案したように、これは美しく機能します。実際のコードで名前の衝突がありました。それを見るのに、さらに1001回目を要しました。関数ポインターが可変であるため、これが機能しないことを示唆する他の StackOverflow 記事に混乱していました。

4

2 に答える 2

4

前提:

あなたの例で、テンプレート引数として使用している変数ではなく、関数besselJの名前である場合、関数ポインタを非型テンプレート引数として渡すと機能するはずです。

実例を参照してください。

代替ソリューション:

関数ポインターが実行時に値が計算される変数に保持されている場合、その関数ポインターをテンプレート引数として使用することはできません。ランタイム関数ポインターを使用する場合は、テンプレート引数ではなく、通常の関数引数を使用できます。

#include <complex>

std::complex<double> diffBessel(
    std::complex<double> (*fxn)(int, std::complex<double>),
    int order,
    std::complex<double> z
    )
{
    return fxn(order-1, z) - fxn(order+1,z);
}

より慣用的な解決策: (C++ 11が必要)

より柔軟性が必要な場合は、C++11で次を使用できますstd::function<>

#include <complex>
#include <functional>

std::complex<double> diffBessel(
    std::function<std::complex<double>(int, std::complex<double>)> fxn,
    int order,
    std::complex<double> z
    )
{
    return fxn(order-1, z)- fxn(order+1,z);
}

どちらの場合も、関数は次のように呼び出すことができます。

int main()
{
    std::complex<double> c;
    /* ... */
    diffBessel(besselH1, 2, c);
}

さらなる可能性:

さらなる可能性として、使用したくない、または使用できない場合はstd::function<>、関数をテンプレートにすることで、呼び出し可能なオブジェクトを受け入れることができます。

template<typename F>
std::complex<double> diffBessel(
    F f,
    int order,
    std::complex<double> z
    )
{
    return f(order-1, z) - f(order+1,z);
}

繰り返しますが、これは以前のバージョンを呼び出したのとまったく同じ方法で呼び出します。

于 2013-03-07T21:44:38.243 に答える
3

テンプレートは、コンパイル時にパラメーターを知る必要があります。実行時に変数からテンプレートパラメータを引き出すことは機能しません。

関数ポインタを関数パラメータにするだけです。テンプレート関数である必要はありません。

std::complex<double> diffBessel(int order,
                                std::complex<double> z,
                                std::complex<double> (*T)(int, std::complex<double>))
于 2013-03-07T21:44:23.600 に答える