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
.
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?
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>
.