Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Avoiding template parameter substitution completely

I have a class that can accept arithmetic types and std::complex. A simplified code of the class is

#include <complex>

template<typename T> struct is_complex : std::false_type {};
template<typename T> struct is_complex<std::complex<T>> : std::true_type {};

template<class T>
struct Foo {
    void foo(typename T::value_type t)
    requires (is_complex<T>::value) {
    }
};

Now, I would like to take the internal type of std::complex and use it as the type of the parameters in the foo function.For example, if T is std::complex<double>, then I want the parameter types to be double.

This function should only be available when T is indeed std::complex.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I thought I could use typename T::value_type as the parameter type, since std::complex has a typedef value_type. Plus, I thought using requires here would avoid T to be substitued in this function in case T wasn’t std::complex. Silly me.
The issue is that whenever I create a Foo<FundamentalType> the code breaks, since fundamentals don’t have ::value_type.

int main() {
    Foo<int> obj; // Breaks the code.
    //obj.foo(4); // Function shouldn't be considered in overload resolution ideally...

    Foo<std::complex<int>> obj2; // Works
    obj2.foo(4); // Works as expected
}

Ideally, I would like the substitution of T to be ignored for this function in case T is not std::complex. Is that possible? If not, how can I circumvent this?

>Solution :

You’re on the right track with is_complex: you’d like the same here, but with a different body of the type. For example,

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

template<typename T>
using complex_value_type_t = typename complex_value_type<T>::type;

Then, at any point, you can call it as complex_value_type_t<T>:

template<class T>
struct Foo {
    template<typename T_ = T>
    void foo(complex_value_type_t<T_> t)
    requires (is_complex<T_>::value) {
    }
};

The requires is not absolutely necessary then; it’s already covered by complex_value_type_t<T> being defined only for complex<T>.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading