简体   繁体   English

使用已经推导出的模板参数来专门化模板成员函数

[英]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. 有一秒钟,我想我可能会尝试将enable_if与return类型一起使用。

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. 但这是行不通的,因为(据我所知)是因为在成员函数的位置已经推导出模板“ T”,并且无法使用SFINAE。 Please correct me if I'm wrong on that. 如果我做错了,请纠正我。

So I guess I could write overloads with true_type and false_type like this: 所以我想我可以这样写true_type和false_type重载:

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> . 但是那些似乎毫无意义地构造了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") 只是让编译器在std::max上进行优化(注意:您应该使用std::max来“避免出现负数”)

For clarification or if normalize is actually more complex, you might do: 为了澄清或者如果normalize实际上更复杂,您可以执行以下操作:

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! 编译器甚至可能足够聪明,可以为您优化对std::max的调用! 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. 如果性能成为问题,则应该概述瓶颈,而不是猜测瓶颈,只有当它表明对未签名类型进行规范化是您的问题所在(我无法想象这是真的)时,您才考虑将其专门化为没事

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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