开发者

C++ template type deduction problem

开发者 https://www.devze.com 2022-12-25 14:31 出处:网络
motivation: I would like to create a utility class so that instead of having to write: if( someVal ==val1 || someVal == val2 || someVal == val3 )

motivation: I would like to create a utility class so that instead of having to write:

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

I could instead write:

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

which is much closer to the mathematical 'a is an element of (b,c,d)' and also would save on a lot of typing when the variable name 'someVal' is long.

Here is the code I have so far (for 2 and 3 values):

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 开发者_JAVA百科t_ == v1 || t_ == v2 || t_ == v3; 
    }
};

However it fails to compile if I write:

is(1).in(3,4,5);

instead I have to write

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

Which isn't too bad, but it would be better if somehow the compiler could figure out that the type is int with out me having to explicitly specify it.

Is there anyway to do this or I am stuck with specifying it explicitly?


If you want to keep this syntax, you can use a helper function like :

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


The problem is quite amusing, it's true that boolean conditions can get hairy.

I myself tend to prefer writing special functions though, because the meaning here is hard to convey. What does:

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

means ?

Is

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

better?

I think it would be easier to read with:

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

I guess it's a matter of style.

The advantages of the second method including:

  • In case the test is done more than once, the logic is not scattered all around (so changes are easy)
  • No need to comment the test, the method name does it already

Inconvients ? I guess it's more typing... oh well :p


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


Regarding the general problem, a utility function like contains might be handy:

#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 usage makes it also accept arrays, although one might write that overload separately. This could also be overloaded for containers with the find member function.)

In C++0x this could be extended to support std::initializer_list<T>* allowing rather nice usage:

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

* Not sure if it shouldn't work already, but my compiler requires an overload to make it work.


You are stuck with it - the constructor requires the type to be provided as a template parameter. And I should observe that I really don't like your idea (especially the class name). Why not use a std:;set? Or even a template function - something like:

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


a modification for your comparison class is perhaps to use varargs, to make it general to n elements of the set.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号