I would like to have a class method that's specialized for either complex or real computations.
Adapting this post on how to use enable_if
and this post on how to discriminate between cuda::std::complex<T>
or T
(or the std::complex
variant) I came up with the following:
#include <type_traits>
#include <typeinfo>
#include <complex>
#include <cuda/std/complex>
#define typestr(T) typeid(T).name()
// https://stackoverflow.com/questions/41438493/how-to-identifying-whether-a-template-argument-is-stdcomplex
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 <typename T>
class TestComplex
{
public:
template <typename Q = T,
typename = typename std::enable_if_t<is_tt<cuda::std::complex, Q>::value, bool>>
void check()
{
std::cout << "complex T: " << typestr(T) << std::endl;
return;
}
template <typename Q = T,
typename = typename std::enable_if_t<!is_tt<cuda::std::complex, Q>::value, bool>>
void check()
{
std::cout << "not complex T: " << typestr(T) << std::endl;
return;
}
};
But this gives me the compiler error (nvcc 11.3, MSVC 2017 19.16)
invalid redeclaration of member function template "void TestComplex<T>::check()"
Playing around a bit (read: a lot) I adapted to the following:
#include <type_traits>
#include <typeinfo>
#include <complex>
#include <iostream>
#define typestr(T) typeid(T).name()
// https://stackoverflow.com/questions/41438493/how-to-identifying-whether-a-template-argument-is-stdcomplex
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 <typename T>
class TestComplex
{
public:
template <typename Q = T>
typename std::enable_if_t<is_tt<std::complex, Q>::value, void> check()
{
std::cout << "complex T: " << typestr(T) << std::endl;
return;
}
template <typename Q = T>
typename std::enable_if_t<!is_tt<std::complex, Q>::value, void> check()
{
std::cout << "not complex T: " << typestr(T) << std::endl;
return;
}
};
int main()
{
using cfloat = std::complex<float>;
TestComplex<float> float_test;
TestComplex<cfloat> cfloat_test;
float_test.check();
cfloat_test.check();
return 0;
}
Output, as expected (with nice msvc defined typenames :):
not complex T: float
complex T: class std::complex<float>
Now my question is, why do I get the redeclaration error in the first case, while I think I am adding the template enable_if to make the compiler aware of different implementations. And, enable_if stuff not being my strong suit, does this make any sense or did I make a mess.