简体   繁体   中英

Specialize template member function with already-deduced template parameter

I want to specialize the member function of a template struct based on the type-traits of the already-deduced struct template parameter. I want one version of the function when the template parameter is signed and another when it's unsigned. Not sure how to go about this.

The struct is simple. It represents a size -- something that's no doubt been written a thousand times. Here's a simple version that I could use for all types, I guess:

template<class T>
struct Size
{
    T cx;
    T cy;

    // ... a bunch of functions you might expect.

    // normalize function -- avoid negative sizes.  make sure size is at LEAST 0, 0

    void normalize()
    {
        cx = std::min(cx, 0);
        cy = std::min(cy, 0);
    }
};

But of course that processing function is pointless for unsigned types. I'd like to make it a no-op for those types.

For a second, I thought I might try using enable_if along with the a return type.

typename std::enable_if<std::is_signed<T>::value, Size&>::type 
normalize() 
{ 
    cx = std::max(cx, 0); 
    cy = std::max(cy, 0); 
    return *this; 
}
typename std::enable_if<std::is_unsigned<T>::value, Size&>::type 
normalize() 
{
    return *this; 
}

But that won't work because (as I understand it) because, at the point of the member function, template 'T' has already been deduced and SFINAE cannot be used. Please correct me if I'm wrong on that.

So I guess I could write overloads with true_type and false_type like this:

void normalize(std::true_type)
{
    // Ensure signed types are at least zero.

    cx = std::max(cx, 0); 
    cy = std::max(cy, 0); 
}
void normalize(std::false_type)
{
    // do nothing for unsigned types
}
void normalize() 
{
    // Call overload based on type.
    normalize(std::is_signed<T>::type()); 
}

But those seem to pointlessly construct a std::integral_constant<bool> . That offends my sense of efficiency. If this were a more complicated example, it might even affect performance.

So instead I could similarly write a member template function like this:

template <typename T> 
void normalizeT() 
{  }

template<> 
void normalizeT<std::true_type>()
{
    cx = std::max(cx, 0); 
    cy = std::max(cy, 0); 
}
void normalize()
{
    normalizeT<std::is_signed<T>::type>();
}

And I'm guessing there are other approaches. But I sort of feel like I'm missing something obvious. I always like to take the time to boil this stuff down to the simplest, clearest, most robust version possible.

I realize it's not a very complicated "problem" here. And as I said, I can already make the code work But I'm looking for the more general lesson -- to understand and recognize the "pattern" involved because this is the sort of situation I find myself in often.

So given those goals, is there a way to write this more cleanly or robustly?

Do not optimize manually (with the template). Just let the compiler optimize on std::max (Note: you should use std::max to "avoid negative sizes")

For clarification or if normalize is actually more complex, you might do:

void normalize()
{
    if(std::is_signed<T>::value) {
        cx = std::max(cx, 0);
        cy = std::max(cy, 0);
        // ...
    }
}

Unless you are perhaps writing for an embedded hard real time system, this is square under the bullet-point of premature optimization. You should write the easy obvious code even if it might seem sub-optimal. The compiler might even be smart enough to optimize away the call to std::max for you! If the program performance is acceptable then nothing lost: You've written code once and everything is fine. If performance becomes an issue then instead of guess at bottlenecks you should profile, and only if it shows that normalize for unsigned types is your problem area (I can't imagine any case where this would be true) would you consider specializing it as a no-op.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM