C ++模板类型演绎问题

时间:2010-04-06 09:20:44

标签: c++ templates

动机:我想创建一个实用程序类,而不必写:

if( someVal ==  val1 || someVal == val2 || someVal == val3 )

我可以写一下:

if( is(someVal).in(val1, val2, val3) )

更接近于数学'a是(b,c,d)'的元素,并且当变量名'someVal'很长时也会节省大量的输入。

这是我到目前为止的代码(对于2和3个值):

template<class T>
class is {
private:
    T t_;
public:
    is(T t) : t_(t) { }

    bool in(const T& v1, const T& v2) { 
        return t_ == v1 || t_ == v2; 
    }
    bool in(const T& v1, const T& v2, const T& v3) { 
        return t_ == v1 || t_ == v2 || t_ == v3; 
    }
};

但是如果我写的话,它就无法编译:

is(1).in(3,4,5);
相反,我必须写

is<int>(1).in(3,4,5);

这不是太糟糕,但如果编译器能够以某种方式判断出类型为int并且我必须明确指定它,那会更好。
无论如何要做到这一点,或者我坚持明确指定它?

6 个答案:

答案 0 :(得分:14)

如果要保留此语法,可以使用辅助函数,如:

template<class T>
class is_op {
private:
    T t_;
public:
    is_op(T t) : t_(t) { }

    bool in(const T& v1, const T& v2) { 
        return t_ == v1 || t_ == v2; 
    }
    bool in(const T& v1, const T& v2, const T& v3) { 
        return t_ == v1 || t_ == v2 || t_ == v3; 
    }
};


template< class U >
inline is_op<U> is( U const& v )
{
    return is_op<U>( v );
}

int main(int argc, char* argv[])
{
    is( 1 ).in( 1 , 2 , 4 );
}

答案 1 :(得分:5)

这个问题非常有趣,布尔条件可能会变得很毛茸茸。

我自己倾向于更喜欢写特殊功能,因为这里的含义很难传达。做什么:

if (someVal == val1 || someVal == val2 || someVal == val3)

意味着什么?

if ( is(someval).in(val1, val2, val3) )
// or
if ( is(someval).in(val1)(val2)(val3) ) // implements short-circuiting
                                        // and removes arity issue
                                        // using a proxy object

更好?

我认为用以下内容阅读会更容易:

bool isToBeLogged(const Foo& foo)
{
  // Either
  static std::set<Foo> ValuesToLog = /* some boost assign magic or whatever */;
  return ValuesToLog.find(foo) != ValuesToLog.end();

  // Or
  return foo == val1 || foo == val2 || foo == val3;
}


if (isToBeLogged(someVal))

我想这是一种风格问题。

第二种方法的优点包括:

  • 如果测试不止一次,逻辑就不会四处分散(所以更改很容易)
  • 无需评论测试,方法名称已经

不健康?我想这更像打字......哦,好吧:p

答案 2 :(得分:1)

template<typename T>
is<T> is_value(T value)
{
    return is<T>(value);
}

int main()
{
    bool r ;

    r = is_value(1).in(3,4,5);
    r = is_value(3).in(3,4,5);

    return 0;
}

答案 3 :(得分:1)

关于一般问题,像contains这样的实用函数可能很方便:

#include <boost/range.hpp>
template <class Range, class T>
bool contains(const Range& range, const T& value)
{
    return std::find(boost::begin(range), boost::end(range), value) != boost::end(range);
}

(Boost的使用使得它也接受数组,尽管可能会单独编写该重载。对于具有find成员函数的容器,这也可能会重载。)

在C ++ 0x中,这可以扩展为支持std::initializer_list<T> *允许相当不错的用法:

if (contains({1, 2, 3}, value) {...}

*不确定它是否应该不起作用,但我的编译器需要重载才能使其正常工作。

答案 4 :(得分:0)

你坚持使用它 - 构造函数需要提供类型作为模板参数。我应该观察到我真的不喜欢你的想法(尤其是班级名称)。为什么不使用std :; set?甚至是模板功能 - 类似于:

template <typename  T>
bool IsIn( T v, T a, T b, T c ) {
   ...
}

答案 5 :(得分:0)

对比较类的修改可能是使用varargs,使其对该集合的n个元素具有通用性。