Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ template type deduction problem

Tags:

c++

templates

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

like image 660
hamishmcn Avatar asked Nov 30 '22 18:11

hamishmcn


2 Answers

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 );
}
like image 115
fa. Avatar answered Dec 10 '22 15:12

fa.


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

like image 40
Matthieu M. Avatar answered Dec 10 '22 14:12

Matthieu M.