__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)));