【问题标题】:Problem with my clamp macro我的钳位宏有问题
【发布时间】:2010-11-04 19:48:16
【问题描述】:

我的钳位宏有问题,当我的值超过 10 并且我的最高值超过 17 时,它会停止工作。有什么想法吗?

#define CLAMP(value, low, high) (((value)<(low))?(low):(((value)>(high))?(high):(value)))

【问题讨论】:

  • 调试宏时首先要做的是展开它,看看为什么会得到不正确的结果。

标签: c++ macros clamp


【解决方案1】:

我建议使用比宏更安全的方法:

template <typename T> T CLAMP(const T& value, const T& low, const T& high) 
{
  return value < low ? low : (value > high ? high : value); 
}

【讨论】:

  • +1,但我建议template &lt;typename V, typename L, typename H&gt;
  • @Beta:这样它将捕获潜在危险的类型转换。但你的方法也行。
  • 几乎没有理由将这样的 if-else-statement 打包到模板函数中。否则+1(我个人不会仅仅因为它替换功能中的宏而将函数命名为全部大写)。
  • 这是迄今为止最好的答案。 Nit:所有大写名称都应保留给宏。干杯,
  • @Beta:标准std::max() 使用单一类型,而不是您建议的三种。在某个时间点,Alexandrescu“仅”用 174 行代码编写了 C 宏 #define MAX( x, y ) ((x)&gt;(y)? (x) : (y)) 的完美正确类型安全版本。标准委员会认为 std::min 模板存在的问题(要求两个参数类型相同,如果参数类型不同则失败)不值得 Alexandrescu 提案所要求的更改。有时简单的方法就足够了。
【解决方案2】:

你的宏没问题。如果您传入小于lowhigh,您会看到奇怪的结果,但这不太可能是原因。

最可能的结果是您传入的表达式具有副作用,例如使用++ 运算符或调用函数。如果您的表达式有副作用,那么由于宏替换的工作方式,副作用可能会发生多次。例如:

CLAMP(x++, low, high)  // expands to:
(x++ < low) ? low : ((x++ > high) ? high : x++);

x++ 被多次评估,这绝对不是您想要的(这是未定义的行为,由于缺少序列点)。

我建议将宏重写为模板:

template <typename T> T CLAMP(T value, T low, T high)
{
    return (value < low) ? low : ((value > high) ? high : value);
}

【讨论】:

  • 为什么还要保留三元运算符?为什么不用两个if 语句和三个return 重写它?
【解决方案3】:

使用已经建议的模板函数是更好的解决方案。

无论如何,如果您遇到此类问题(无论是宏还是函数),您都应该简化表达式;看看这个伪代码:

max(a,b): a>b ? a : b
min(a,b): a<b ? a : b
clamp(x,lo,hi): min( hi, max(lo,x) )

【讨论】:

    【解决方案4】:

    您也可以将其设为inline 函数,这样它就可以像宏一样但更安全。

    【讨论】:

    • 这个答案与问题无关。
    猜你喜欢
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    相关资源
    最近更新 更多