2010-04-06 96 views
4

动机:我想创建一个实用工具类,以便而不必写:C++模板类型推演问题

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

这并不算太坏,但如果编译器能够发现类型为会更好无需我明确指定它。
有没有办法做到这一点或我坚持明确指定它?

回答

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

典型的方法是编写提供功能的类,然后编写一个函数来创建实例该类自函数支持类型推导。 – 2010-04-06 09:35:09

0

你一直坚持它 - 构造函数要求提供的类型作为模板参数。我应该看到,我真的不喜欢你的想法(尤其是班级名称)。为什么不使用std:; set?甚至一个模板函数 - 是这样的:

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

事实上,我从类似于IsIn的东西开始,因为一个名为'in'的类似乎在寻求麻烦,但最终我决定为了可读性而选择(a).in(b,c)。重新使用std :: set - 我的用例是我希望能够在一行中做到这一点,不必向该集合添加成员,然后检查成员资格。 (顺便说一下,我没有downvote你) – hamishmcn 2010-04-06 09:44:40

+0

关于类名:把它放在一个名称空间,它会好吗? (它有多大可能是C++会得到一个**是**关键字?!是不是所有人都称之为istreams?) – UncleBens 2010-04-06 13:28:32

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

我想这是一个风格问题。

第二种方法的优点包括:

  • 万一测试超过一次,逻辑是不是散落各地的(这样的改变很容易)
  • 无需置评测试,方法名称是否已经

Inconvients?我想这是更多的打字......哦,很好:p

+0

我不知道你会如何实现短路?您不会传递函数调用的结果,而是查找时调用函数的对象? - 但一般来说,你不能结合这些方法(使用is.in来实现isToBeLogged)吗? – UncleBens 2010-04-06 11:46:39

0

您的比较类的修改可能是使用可变参数,使其通用于n个元素集。

+0

可变参数不适用于大多数类型的T? C++ 0x中的变量模板或'initializer_list'是另一回事。 – UncleBens 2010-04-06 13:30:35

1

对于广大的问题,就像一个效用函数中包含可能会派上用场:

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

(升压使用使得它也接受阵列,尽管人们可能会单独写超载这也可能过载与容器。 。查找成员函数)

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

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

*不知道它是否应该不能工作,但我的编译器需要重载才能使其工作。