0

I need to implement a class, say 'MyClass' using templates.

template<class T>
class MyClass
{
public:


          T var1;
          T1 var2;
        };

There are two member variables var1 and var2. If the class template argument, 'T', is fundamental type (eg: float, double or long double), the types of both the variables var1 and var2 should be the same as the template argument. That is T1 = T in the above example.

But if the template argument is std::complex<T>, I would like to have

T var1;
std::complex<T> var2;

How to implement it in C++11?

max66
  • 65,235
  • 10
  • 71
  • 111
Soo
  • 885
  • 7
  • 26

1 Answers1

7

A possible solution could be define a simple type traits to extract the correct type

template <typename T>
struct myTypeTraits
 { using type = T; };

template <typename T>
struct myTypeTraits<std::complex<T>>
 { using type = T; };

and MyClass become

template <typename T>
class MyClass
 {
   using T0 = typename myTypeTraits<T>::type;

   T0 var1;
   T  var2;
 };

If you want to be sure that T is a fundamental type (or do you mean arithmetic?), is a little more complicated.

A possible way is define a type traits to say (true or false) if a type is a std::complex

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

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

Next modify myTypeTraits with a declaration (no generic definition) and two default bool values

template <typename T, bool = std::is_fundamental<T>::value, 
                      bool = isComplex<T>::value>
struct myTypeTraits;

Next two specializations, the first one for fundamentals and the second one for complexes types

template <typename T>
struct myTypeTraits<T, true, false>
 { using type = T; };

template <typename T>
struct myTypeTraits<std::complex<T>, false, true>
 { using type = T; };

The MyClass class remain equals but now give an error if you try to instantiate it with (by example) a std::string.

The following is a full compiling example

#include <complex>
#include <type_traits>

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

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

template <typename T, bool = std::is_fundamental<T>::value, 
                      bool = isComplex<T>::value>
struct myTypeTraits;

template <typename T>
struct myTypeTraits<T, true, false>
 { using type = T; };

template <typename T>
struct myTypeTraits<std::complex<T>, false, true>
 { using type = T; };

template <typename T>
class MyClass
 {
   public:  // public to check with the static_assert()
      using T0 = typename myTypeTraits<T>::type;

   private:
      T0 var1;
      T  var2;
 };

int main ()
 {
   MyClass<int>                  mi; // compile
   MyClass<std::complex<float>>  mc; // compile
   // MyClass<std::string>          ms; // compilation error

   static_assert( std::is_same<int, decltype(mi)::T0>{}, "!" );
   static_assert( std::is_same<float, decltype(mc)::T0>{}, "!" );
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • Excellent! Thanks for the answer. However, I just realized that I should have member functions which again depends on the template parameters. Can you please provide and elegant solution for this too? – Soo Nov 16 '17 at 17:35
  • @Soo - if you have a lot of differences, you should consider to partial specialize the entire `MyClass` (as suggested by Quentin); but if you want a help for "member functions which again depends on the template parameters", sorry but it's too generic; I suggest you to modify the question, with a specific example, or ask it in another question. – max66 Nov 16 '17 at 17:47