I'm trying to implement a template specialization for complex
scalars and, with the help of Stackoverflow, got to using std::enable_if_t
and its poor man's version
#include <type_traits>
#include <complex>
// declarations
namespace Test {
template<class Scalar>
class A {
public:
A(const Scalar z);
Scalar realPart();
private:
Scalar z_;
};
}
// definitions
namespace Test {
template<bool B, class T = void>
using enable_if_t = typename std::enable_if<B,T>::type;
template<class T> struct is_complex : std::false_type {};
template<class T> struct is_complex<std::complex<T>> : std::true_type {};
template<class Scalar>
A<Scalar>::
A(const Scalar z) : z_(z)
{ }
template<class S = Scalar, enable_if_t<is_complex<S>{}>* = nullptr>
Scalar
A<Scalar>::realPart()
{
return z_.real();
}
template<class S = Scalar, enable_if_t<!is_complex<S>{}>* = nullptr>
Scalar
A<Scalar>::realPart()
{
return z_;
}
}
int main() {
}
for C++11. The above code, separating declarations and definitions, however, fails to compile with
test4.cpp:29:22: error: ‘Scalar’ does not name a type
template<class S = Scalar, enable_if_t<is_complex<S>{}>* = nullptr>
^
It's not clear to me how this fails. Any hints?
In this code:
Scalar
doesn't name a type because it isn't one. That's just the name of a template parameter that you've been using. What you had intended to write was:However, this won't work either, since
A
doesn't have a second template non-type argument and you're trying to pass it one. What you're really trying to do is partially specialize the member functionA<Scalar>::realPart()
and that's impossible in the language.What you need to do instead is dispatch to a helper that will know what to do. Something like:
with:
With a more complicated type trait, we'd do something like:
And have overloads taking
true_type
andfalse_type
as the second argument. In this particular case, that's unnecessary.