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

时间:2016-02-05 17:28:37

标签: c++ templates c++11

我想根据已经推导出的struct template参数的类型特征来专门化模板结构的成员函数。我想在模板参数签名时使用该函数的一个版本,而在未签名时需要另一个版本的函数。不确定如何解决这个问题。

结构很简单。它代表了一种尺寸 - 这无疑是写了一千次。这是一个我可以用于所有类型的简单版本,我想:

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

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

我意识到这不是一个非常复杂的“问题”。正如我所说,我已经可以使代码工作但我正在寻找更一般的教训 - 理解并认识到所涉及的“模式”,因为这是我经常遇到的那种情况。

所以考虑到这些目标,有没有办法更清洁或更健壮地写出来?

2 个答案:

答案 0 :(得分:0)

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

为了澄清或normalize实际上更复杂,您可以这样做:

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

答案 1 :(得分:0)

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