6

valarray関数のポインター コードで問題が発生しています。

double (*fp)(double) = sin;
valarray<double> (*fp)(const valarray<double> &) = sin;

最初はコンパイルされ、2 番目は次のようになります。

error: no matches converting function 'sin' to type 'class std::valarray<double> (*)(const class std::valarray<double>&)'
4

3 に答える 3

11

__typeof__これは、 GCC 拡張機能を使用してコンパイルされます。GCCvalarrayは式テンプレートを使用して副鼻腔の計算を遅らせているようです。sinしかし、それはテンプレートの戻り値の型を正確valarray<T>ではなく、奇妙な複雑な型にします。

#include <valarray>

template<typename T> struct id { typedef T type; };
int main() {
  using std::valarray;
  using std::sin;

  id<__typeof__(sin(valarray<double>()))>::type (*fp)(const valarray<double> &) = sin;
}

編集: GCC がそれを行うのに問題がない理由については、AProgrammer の標準的な引用を参照してください。

編集:標準準拠の回避策

厳密に標準に準拠した方法なし__typeof__でこれを行うのは少し注意が必要です。の戻り値の型を取得する必要がありますsin。Eric Nieblerが示したように、これには条件演算子を使用できます。sin関数を実際に呼び出すのではなく、型チェックのみを行うことで機能します。条件演算子のもう一方の分岐 (実際に評価される分岐) を同じ型に変換することで、関数ポインターの型を推測できるようにするためだけにダミー パラメーターを生成できます。

#include <valarray>

using std::valarray;

template<typename T> struct id {
  typedef T type;
};

struct ded_ty {
  template<typename T>
  operator id<T>() { return id<T>(); }
};

template<typename E, typename T>
id<T(*)(valarray<E> const&)> genFTy(T t) { 
  return id<T(*)(valarray<E> const&)>(); 
}

template<typename T>
void work(T fp, id<T>) {
  // T is the function pointer type, fp points
  // to the math function.
}

int main() {
  work(std::sin, 1 ? ded_ty() : genFTy<double>(std::sin(valarray<double>())));
}

すぐにアドレスを取得したい場合は、再度work返すように記述できますfp

template<typename T>
T addy(T fp, id<T>) { return fp; }

これで、最終的にマクロを作成して条件演算子のトリックをカプセル化し、そのような数学関数のアドレスを取得するときに使用できます。

#define DEDUCE(FN,Y) (1 ? ded_ty() : genFTy<Y>(FN(std::valarray<Y>())))

アドレスを取得して汎用関数に渡すには、次のようにします。

std::transform(v1.begin(), v1.end(), v1.begin(),
  addy(std::sin, DEDUCE(std::sin, double)));
std::transform(v2.begin(), v2.end(), v2.begin(),
  addy(std::cos, DEDUCE(std::cos, double)));
于 2009-08-30T12:53:54.070 に答える
10

26 3.1/3

valarray を返すすべての関数は、valarray のすべての const メンバー関数もこの型に適用できる場合、別の型のオブジェクトを返すことができます。

目的は、結果を最適化するためにテンプレート式を使用できるようにすることです (つまり、配列全体で 1 回ループし、毎回計算を行い、一時的なものを構築する代わりに、結果の valarray<> に直接代入します)。

z = sin(x+y);

に最適化できます

for (i = 0; i < N; ++i)
   z[i] = sin(x[i] + y[i]);
于 2009-08-30T12:52:05.567 に答える
4

タイトルで話しますstd::sinが、次に割り当て::sinます。

valarray<double> (*fp)(const valarray<double> &) = std::sin;

それはうまくいくはずです。のすべての使用を修飾する必要があることに注意してくださいsin。ただし、ほとんどの実装では、名前を含めてもグローバル名前空間に名前が挿入されます<cmath>(これは非標準の動作です)。

編集:残念ながら、あなたは運が悪いです。規格はsin(valarray<T> const &)次のことについて述べています(26.3.3.3)。

この関数は、T 型の値、または T 型に明確に変換できる値を返します。

gcc によって実行される最適化は、標準によって許可されています。上記のコードの動作は保証されていません。

于 2009-08-30T12:34:14.017 に答える