10

I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this

template <typename T>
class A
{  
public:
    void foo(std::vector<std::complex<T>>& result);
};

Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like

void foo(std::vector<std::complex<float>>& result);

and not like

void foo(std::vector<std::complex<std::complex<float>>>& result);

Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice? What is the most elegant way to solve this issue?

zimmerrol
  • 4,872
  • 3
  • 22
  • 41

2 Answers2

6

Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type

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

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

and use it in A (see fT)

template <typename T>
class A
 {  
   public:
      using fT = typename getFloatType<T>::type;

      void foo(std::vector<std::complex<fT>>& result)
       { }
 };
Constructor
  • 7,273
  • 2
  • 24
  • 66
max66
  • 65,235
  • 10
  • 71
  • 111
  • Are these two ways equal, or is one of them the preferred way to do this? – zimmerrol Oct 28 '17 at 12:56
  • @FlashTek - they are really different; in this way you can avoid to create a specialization that can be an advantage; but a specialization can be needed for other reasons; in this toy example I think it's preferred the type traits way; but for your real (I suppose more complex) necessity, the specialization way can be preferable. Only you can give and answer to your question. – max66 Oct 28 '17 at 12:59
  • @FlashTek If you just want to change the signature of `foo` then this one is simpler. With partial specialization you can customize more things, but as you asked you have to handle the duplicated codes between primary template and partial specialization. – songyuanyao Oct 28 '17 at 13:00
1

You can make a partial specialization for any instantiation of std::complex, e.g.

template <typename T>
class A<std::complex<T>>
{  
public:
    void foo(std::vector<std::complex<T>>& result);
};

Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.

To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.

class Base {
public:
    void bar(...);
};

then

template <typename T>
class A : public Base {
    ...
};

template <typename T>
class A<std::complex<T>> : public Base {
    ...
};
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Assuming I have other functions inside the `A` class, do I need to add the definitions of these in the partial specification, too? – zimmerrol Oct 28 '17 at 12:42
  • @FlashTek Yes. You can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. – songyuanyao Oct 28 '17 at 12:45
  • When I declare the function inside a header, and define it in the body/cpp, can I reuse the code, or do I need to add the definition inside the cpp twice? – zimmerrol Oct 29 '17 at 19:07
  • @FlashTek If you define it in a cpp you will run into problems. – LeDYoM Oct 29 '17 at 22:12
  • @FlashTek Yes you can declare firstly, and define later. But you'd better put them all in header file. See [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file?rq=1) – songyuanyao Oct 30 '17 at 00:25
  • But when I store it all in the header I cannot reuse the code, correct? – zimmerrol Oct 30 '17 at 00:34
  • @FlashTek What do you mean can't reuse? You can include the header file and use them ? – songyuanyao Oct 30 '17 at 00:37
  • No, by reusing I meant to use the same code/definition for the same function, once for the general template class and once for the specialized class. – zimmerrol Oct 30 '17 at 00:39
  • @FlashTek As I said, you can add a base class for common code. For templates, you'd better declare and implement all in header file, Ohterwise, you can declare in header and implement in cpp file as the usual class. – songyuanyao Oct 30 '17 at 00:44
  • @FlashTek I added a draft about duplicated code. Is that clear? – songyuanyao Oct 30 '17 at 00:51