How to identifying whether a template argument is std::complex?

2.6k views Asked by At

How to identify whether a template parameter is std::complex? I want a general method which supports all data types like float, double, int, etc. I know that using std::is_same I can check specifically for a given type, for example, std::complex<float>. But here I require a general method.

4

There are 4 answers

0
W.F. On BEST ANSWER

As I understand your question you are looking for implementation of a general method to test if a given type is specialization of given template template type. This can be done using class template somewhat like in Frank's answer. I will present you complementary approach to specialization - template type alias with function overloading:

#include <type_traits>
#include <complex>
#include <iostream>

template <template <class...> class TT, class... Args>
std::true_type is_tt_impl(TT<Args...>);
template <template <class...> class TT>
std::false_type is_tt_impl(...);

template <template <class...> class TT, class T>
using is_tt = decltype(is_tt_impl<TT>(std::declval<typename std::decay<T>::type>()));

int main() {
    static_assert(is_tt<std::complex, std::complex<int>>::value, "!");
    static_assert(is_tt<std::complex, std::complex<float>>::value, "!");
    static_assert(!is_tt<std::complex, float>::value, "!");
}

[live demo]

You can utilize the trait as follows:

#include <type_traits>
#include <complex>
#include <iostream>

//complementary approach to specialization one would be to use function overloading
template <template <class...> class TT, class... Args>
std::true_type is_tt_impl(TT<Args...>);
template <template <class...> class TT>
std::false_type is_tt_impl(...);

template <template <class...> class TT, class T>
using is_tt = decltype(is_tt_impl<TT>(std::declval<typename std::decay<T>::type>()));

template <class T>
typename std::enable_if<is_tt<std::complex, T>::value>::type print(T t) {
    std::cout << "(" << t.real() << "," << t.imag() << ")" << std::endl;
}

template <class T>
typename std::enable_if<!is_tt<std::complex, T>::value>::type print(T t) {
    std::cout << t << std::endl;
}


int main() {
    print(std::complex<int>(1, 2));
    print(std::complex<double>(1.5, 2.5));
    print(5.5);
}

(1,2)
(1.5,2.5)
5.5

[live demo]

0
AudioBubble On

This can be done using partial template specialization.

First you define a catch-all template that defaults to false:

template<typename T>
struct is_complex_t : public std::false_type {};

Then you provide an overload for types that match your condition:

template<typename T>
struct is_complex_t<std::complex<T>> : public std::true_type {};

I also like to add a utility function as well:

template<typename T>
constexpr bool is_complex() { return is_complex_t<T>::value; }

Edit: This utility function is not needed or usefull with c++14 and up, as std::integral_type implements operator().

Usage:

bool int_is_complex = is_complex<int>(); //false
bool complex_is_complex = is_complex<std::complex<float>>(); //true
0
skypjack On

You can base your solution on a tag dispatching technique.
Here follows a minimal, working example:

#include<complex>
#include<utility>
#include<iostream>

class C {
    template<typename T>
    void f(int, std::complex<T>) {
        std::cout << "complex" << std::endl;
    }

    template<typename T>
    void f(char, T &&t) {
        std::cout << "something else" << std::endl;
    }

public:
    template<typename T>
    void f(T &&t) {
        f(0, std::forward<T>(t));
    }
};

int main() {
    C c;
    c.f(0);
    c.f(std::complex<float>{});
}

This gives you a general method f that accepts almost anything and dispatches internally to the right function.

2
Janek_Kozicki On

This one works too: Live Demo

#include <boost/type_traits/is_complex.hpp>
#include <iostream>
#include <complex>
int main() {
    std::cout << std::boolalpha;
    std::cout << boost::is_complex<std::complex<float>>::value << "\n";
    std::cout << boost::is_complex<long double>::value << "\n";
}