Search code examples
c++c++11complex-numbers

Apply std::conj in template function if template argument is complex


TL;DR Let's say I have a function with a template argument T that takes a std::vector<T>& as input (see below), I want to conjugate this vector, if T is a complex type. How can I do that ?

What I have tried Following https://stackoverflow.com/a/30737105/5913047, I know I can check if a type is complex with

template<class T> struct is_complex : std::false_type {};
template<class T> struct is_complex<std::complex<T>> : std::true_type {};

So I tried:

template<typename T>
void MyFunction(std::vector<T>& MyVector){
    // do something
    if (is_complex<T>()){
       std::transform(MyVector.begin(), MyVector.end(), MyVector.begin(),[](T&c){return std::conj(c););
    }
}

but then, if I use this function with a non complex type, the compiler says that conj is not defined for non complex type. Is there some design to do what I want ?


Solution

  • You are using an if statement. This requires the code in the if branch to be compilable, even if you don't need it to be executed.

    In c++17, to conditionally compile a piece of code, you can use if constexpr like this:

    if constexpr (is_complex<T>()) {
     //^^^^^^^^^   
        std::transform(MyVector.begin(), MyVector.end(), MyVector.begin(),[](T&c){ return std::conj(c); });
    }
    

    Here's a demo.

    In c++11, you can use std::enable_if to write overloads for the case where the type is non-complex, like this:

    template<typename T, typename std::enable_if<!is_complex<T>::value, int>::type = 0>
    void MyFunction(std::vector<T>& MyVector){
        // do something
    }
    
    template<typename T,  typename std::enable_if<is_complex<T>::value, int>::type = 0>
    void MyFunction(std::vector<T>& MyVector){
        // do something
        std::transform(MyVector.begin(), MyVector.end(), MyVector.begin(),[](T&c){ return std::conj(c); });
    }
    

    Here'a a demo.