【问题标题】:c++ generic way to check a value in a rangec ++通用方法检查范围内的值
【发布时间】:2013-04-26 16:54:06
【问题描述】:

在数学中有不同类型的范围:它们可以是打开的( (a, b) )、关闭的( [a, b] )、左打开的(a, b] )或右打开的( [a, b) )。

我想用 C++(不是 11)编写一个模板函数,可以轻松管理这些情况。但我对元编程和模板不太有信心。

我想要这样的东西:

const int max = MAX, int min = MIN;
int x = value;
// check close range
if ( is_in_range( x, min, max ) ) //...

if ( is_in_range( x, min, max, open) ) //...
if ( is_in_range( x, min, max, left_open) ) //...
if ( is_in_range( x, min, max, right_open) ) //...

有人有什么建议吗?

编辑 1

我试过了,但无法编译

enum { range_open, range_close, range_left_open, range_right_open };

namespace detail {

    template < typename Type >
    inline bool check_open_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min < x ) && ( x < max );
    }

    template < typename Type >
    inline bool check_close_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min <= x ) && ( x <= max );
    }

    template < typename Type >
    inline bool check_left_open_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min < x ) && ( x <= max );
    }

    template < typename Type >
    inline bool check_right_open_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min <= x ) && ( x < max );
    }

 }

template < typename Type, int range_open >
inline bool check_range( const Type& x, const Type& max, const Type& min );

template < typename Type, range_open >
inline bool check_range( const Type& x, const Type& max, const Type& min )
{
    return detail::check_open_range( x, min, max );
}

template < typename Type, range_close >
inline bool check_range( const Type& x, const Type& max, const Type& min )
{
    return detail::check_close_range( x, min, max );
}

template < typename Type, check_left_open_range >
inline bool check_range( const Type& x, const Type& max, const Type& min )
{
    return detail::check_left_open_range( x, min, max );
}

template < typename Type, check_right_open_range >
inline bool check_range( const Type& x, const Type& max, const Type& min )
{
    return detail::check_right_open_range( x, min, max );
}

但实际上使用 4 个重载函数更简单

编辑 2

namespace detail {

    template < typename Type >
    inline bool check_open_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min < x ) && ( x < max );
    }

    template < typename Type >
    inline bool check_close_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min <= x ) && ( x <= max );
    }

    template < typename Type >
    inline bool check_left_open_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min < x ) && ( x <= max );
    }

    template < typename Type >
    inline bool check_right_open_range( const Type& x, const Type& max, const Type& min )
    {
        return ( min <= x ) && ( x < max );
    }
}

struct range_open {};
struct range_close {};
struct left_open_range {};
struct right_open_range {};

template < typename Type >
inline bool check_range( const Type& x, const Type& max, const Type& min)
{
    return detail::check_open_range( x, min, max );
}

template < typename Type >
inline bool check_range( const Type& x, const Type& max, const Type& min, const range_open&)
{
    return detail::check_open_range( x, min, max );
}

template < typename Type >
inline bool check_range( const Type& x, const Type& max, const Type& min, const range_close& )
{
    return detail::check_close_range( x, min, max );
}

template < typename Type >
inline bool check_range( const Type& x, const Type& max, const Type& min, const left_open_range& )
{
    return detail::check_left_open_range( x, min, max );
}

template < typename Type >
inline bool check_range( const Type& x, const Type& max, const Type& min, const right_open_range& )
{
    return detail::check_right_open_range( x, min, max );
}

我觉得Edit 2是对的……

编辑3:好版本

结构 left_open { 模板 static bool compare (const T& value, const T& range) { return range

struct left_close {
    template <class T>
    static bool compare (const T& value, const T& range) { return range <= value; }
};

struct right_open  {
    template <class T>
    static bool compare (const T& value, const T& range) { return value < range; }
};

struct right_close {
    template <class T>
    static bool compare (const T& value, const T& range) { return value <= range; }
}; 

template <class L, class R, class T>
bool check_range(const T& value, const T& min, const T& max)
{
    return L::compare <T> (value, min) && R::compare <T> (value, max);
}

【问题讨论】:

  • 你需要元编程吗?
  • 看起来您想在运行时确定范围的“开放性”(关闭/打开/left_open/right_open)。这是故意的吗,还是您在编写代码时也可以决定?
  • 在模板元编程中,&lt;&gt; 通常用于代替()(然后必须手动检索结果值)
  • STL 中是否有可用的东西来检查范围?

标签: c++ templates


【解决方案1】:

这里有一些适用于 VS2010 的东西:-

class LeftOpen 
{
public:
  template <class T>
  static bool Compare (const T value, const T range) { return value >= range; }
};

class LeftClosed
{
public:
  template <class T>
  static bool Compare (const T value, const T range) { return value > range; }
};

class RightOpen 
{
public:
  template <class T>
  static bool Compare (const T value, const T range) { return value <= range; }
};

class RightClosed
{
public:
  template <class T>
  static bool Compare (const T value, const T range) { return value < range; }
};

template <class L, class R, class T>
bool IsInRange (T value, T min, T max) { return L::Compare <T> (value, min) && R::Compare <T> (value, max); }

int main()
{
  int
    min = 5,
    max = 99;

  bool
    r1 = IsInRange <LeftOpen, RightOpen> (-19, min, max),
    r2 = IsInRange <LeftOpen, RightOpen> (45, min, max),
    r3 = IsInRange <LeftOpen, RightOpen> (149, min, max);
}

【讨论】:

  • 好的...我正在搜索...但它是标准 C++ 吗?可以用g++或者clang编译吗?
  • @elvis.dukaj:应该可以,它对任何事情都不是很“聪明”。唯一的问题可能是将第三个模板参数减去 IsInRange,您可以显式添加。
  • @Skizz,gcc 抱怨显式调用 L::Compare 。只需删除 即可。不知道为什么
  • 用 const T& 值替换 const T 值,用 const T& 值替换 T 值好吗?
【解决方案2】:

一个简单的解决方案是使用重载:

namespace range_policy
{
  struct open {};
  struct left_open {};
  struct right_open {};
  ...
};

template <typename T>
bool is_in_range(const T& a, const T& min, const T& max, range_policy::open) { .... }

template <typename T>
bool is_in_range(const T& a, const T& min, const T& max, range_policy::left_open) { .... }

每个is_in_range 重载都会相应地实现。

在 C++11 中,您可以考虑使用强类型枚举而不是虚拟的 structs

enum class range_policy {open, left_open, right_open, ....};

【讨论】:

  • 他似乎想让范围函数通用所有类型,而不仅仅是 int。
  • @Chethan 很好,这只是一个细节。已编辑。
  • 是的,它必须适用于定义的任何类型
【解决方案3】:

您可以考虑模板编程的标签调度技术。您的 is_in_range 函数将有 4 个重载,每个重载都由一个参数(函数中未使用)来区分,以选择正确的重载。每个重载都可以简单地增加/减少最小值/最大值以达到您所追求的范围。

【讨论】:

    【解决方案4】:

    对此进行枚举。

    enum RangeType
    {
       close,
       open,
       left_open,
       right_open
    }
    
    bool is_in_range(int x, int min, int max, RangeType type) { }
    

    【讨论】:

    • 他似乎想让范围函数通用所有类型,而不仅仅是 int。
    猜你喜欢
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    相关资源
    最近更新 更多