代码之家  ›  专栏  ›  技术社区  ›  Robert Karl

如何引用std::sin(const valarray<double>&)?

  •  6
  • Robert Karl  · 技术社区  · 15 年前

    我有些问题 valarray 函数指针代码:

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

    第一个汇编,第二个给出:

    error: no matches converting function 'sin' to type 'class std::valarray<double> (*)(const class std::valarray<double>&)'
    
    3 回复  |  直到 15 年前
        1
  •  11
  •   Johannes Schaub - litb    15 年前

    它使用 __typeof__ 海湾合作委员会延长。看起来像GCC的 valarray 使用表达式模板延迟窦的计算。但这将使返回类型 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做得很好的原因,请参见相关人员的标准报价。

    编辑: 符合标准的解决方案

    做这个没有 α型 严格的标准一致性有点棘手。您需要获取返回类型 . 您可以使用条件运算符,如Eric Niebler has shown . 它的工作原理是 实际上没有调用函数,但只检查了类型。通过尝试将条件运算符的另一个分支(实际计算的分支)转换为同一类型,我们可以生成一个伪参数,以便能够推断函数指针的类型:

    #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)));
    
        2
  •  10
  •   AProgrammer    15 年前

    26 3.1/3

    任何返回valarray的函数都允许返回另一类型的对象, 前提是valarray的所有const成员函数也适用于此类型。

    其目的是允许使用模板表达式来优化结果(即,在整个数组上循环一次,每次执行计算,直接分配给结果valarray<>,而不是构建临时的)。

    z = sin(x+y);
    

    可以优化到

    for (i = 0; i < N; ++i)
       z[i] = sin(x[i] + y[i]);
    
        3
  •  4
  •   avakar    15 年前

    你说 std::sin 在标题中,但然后分配 ::sin .

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

    那应该管用。注意,您应该限定 sin 尽管大多数实现都会将名称注入全局命名空间,即使包括 <cmath> (这是非标准行为)。

    编辑:不幸的是,你运气不好。标准规定 sin(valarray<T> const &) 以下(26.3.3.3)。

    此函数应返回类型为t或可以明确表示的值。 转换为T型。

    标准允许由GCC执行的优化。以上代码不保证有效。