0

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.

rinkert
  • 6,593
  • 2
  • 12
  • 31
  • [Dupe1](https://stackoverflow.com/questions/61349218/simple-sfinae-problem-conditionally-declaring-member-function), [Dupe2](https://stackoverflow.com/questions/6972368/stdenable-if-to-conditionally-compile-a-member-function) – Jason Jul 20 '22 at 13:48
  • @AnoopRana thx, sorry couldnt find it – rinkert Jul 20 '22 at 13:50

0 Answers0