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

Specialize template member function with already-deduced template parameter

本文关键字:参数 成员 函数 专门化      更新时间:2023-10-16

我想根据已经推导的结构模板参数的类型特征来专门化模板结构的成员函数。 当模板参数有符号时,我想要一个版本的函数,当它没有符号时,我想要另一个版本的函数。 不知道该怎么做。

结构很简单。 它代表了一个大小 - 毫无疑问,它已经被写了一千次。 我想这是一个我可以用于所有类型的简单版本:

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);
    }
};

但是,当然,对于无符号类型,处理函数毫无意义。 我想让它成为这些类型的禁区。

有一秒钟,我想我可能会尝试将enable_if与返回类型一起使用。

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; 
}

但这行不通,因为(据我了解(因为在成员函数的点上,模板"T"已经被推导出来,不能使用 SFINAE。 如果我错了,请纠正我。

所以我想我可以用这样的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()); 
}

但这些似乎毫无意义地构建了一个std::integral_constant<bool>. 这冒犯了我的效率感。 如果这是一个更复杂的示例,它甚至可能会影响性能。

因此,我可以类似地编写如下所示的成员模板函数:

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>();
}

我猜还有其他方法。 但我觉得我错过了一些明显的东西。 我总是喜欢花时间把这些东西归结为最简单、最清晰、最强大的版本。

我意识到这不是一个非常复杂的"问题"。 正如我所说,我已经可以让代码工作了,但我正在寻找更普遍的教训 - 理解和识别所涉及的"模式",因为这是我经常遇到的情况。

因此,鉴于这些目标,有没有办法更干净或更健壮地编写它?

不要手动优化(使用模板(。只需让编译器在std::max上进行优化(注意:您应该使用std::max来"避免负大小"(

为了澄清起见,或者如果normalize实际上更复杂,您可以执行以下操作:

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

除非你正在为嵌入式硬实时系统编写,否则这是过早优化的要点。你应该编写简单明了的代码,即使它看起来不是最佳的。编译器甚至可能足够聪明,可以为您优化对std::max的调用!如果程序性能可以接受,那么就不会丢失任何内容:您已经编写了一次代码,一切都很好。如果性能成为一个问题,那么您应该分析的不是猜测瓶颈,并且只有当它表明无符号类型的规范化是您的问题领域(我无法想象任何情况都是如此(时,您才会考虑将其专门化为无操作。