How do I refer to std::sin(const valarray &)?

后端 未结 3 446
故里飘歌
故里飘歌 2020-12-19 08:18

I\'m having trouble with some valarray function pointer code:

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


        
3条回答
  •  时光说笑
    2020-12-19 09:11

    This compiles, using the __typeof__ GCC extension. Looks like GCC's valarray uses expression templates to delay calculation of the sinus. But that will make the return type of the sin template not exactly valarray, but rather some weird complex type.

    #include 
    
    template struct id { typedef T type; };
    int main() {
      using std::valarray;
      using std::sin;
    
      id<__typeof__(sin(valarray()))>::type (*fp)(const valarray &) = sin;
    }
    

    Edit: See AProgrammer's standard quote for why GCC is fine doing that.

    Edit: Standard compliant workaround

    Doing this without __typeof__ in a strictly Standard conforming way is a bit tricky. You will need to get the return type of sin. You can use the conditional operator for this, as Eric Niebler has shown. It works by having the sin function not actually called, but only type-checked. By trying to convert the other branch (the one which is actually evaluated) of the conditional operator to that same type, we can generate a dummy parameter just to be able to deduce the type of the function pointer:

    #include 
    
    using std::valarray;
    
    template struct id {
      typedef T type;
    };
    
    struct ded_ty {
      template
      operator id() { return id(); }
    };
    
    template
    id const&)> genFTy(T t) { 
      return id const&)>(); 
    }
    
    template
    void work(T fp, id) {
      // T is the function pointer type, fp points
      // to the math function.
    }
    
    int main() {
      work(std::sin, 1 ? ded_ty() : genFTy(std::sin(valarray())));
    }
    

    If you want to get the address right away, you can write work so it returns fp again.

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

    Now, you can finally write a macro to encapsulate the conditional operator trickery, and use it when you want to get the address of any such math function.

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

    To get the address and pass it to some generic function, the following works then

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

提交回复
热议问题