Help with template find_if predicate

M

mikets

Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

Thanks,

Mike.
 
C

Cy Edmunds

mikets said:
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

Thanks,

Mike.

It's a little tricky because we must deal with various types which happen to
have a method called "name". But it can be done with templates:

template <typename NAMED>
class MatchName
{
private:
std::string
m_name;

public:
MatchName(const NAMED &i_named) : m_name(i_named.name()) {}

bool
operator () (const NAMED &other) const {return other.name() == m_name;}
};

template <typename ITER, typename NAMED>
ITER
find_by_name(ITER first, ITER last, const NAMED &target)
{
return std::find_if(first, last, MatchName<NAMED>(target));
}

You call it like this:

find_by_name(v.begin(), v.end(), Person("Melvin"))

where "Person" is a class with a method called "name".
 
H

Howard Hinnant

mikets said:
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

Here's one way to do it using std::tr1::bind:

std::vector<A>::iterator i =
std::find_if
(
myvec.begin(),
myvec.end(),
std::tr1::bind
(
std::equal_to<std::string>(),
std::tr1::bind
(
&A::name,
_1
),
"myname"
)
);

You can also find bind at www.boost.org.

-Howard
 
C

CrayzeeWulf

mikets said:
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.
Here is a candidate predicate:


template < class T,
class ConstType,
const ConstType (T::*method)() >
class EqualThruMemFunc {
public:
EqualThruMemFunc( const ConstType& value ) :
mValue( value ) { }
bool operator()( T& instance ) {
return (instance.*method)() == mValue ;
}
private:
const ConstType& mValue ;
} ;

class Foo {
public
// ...
const std::string name() ;
} ;

// ...

typedef vector<Foo> MyVecType ;
//
MyVecType myvec ;

MyVecType::iterator it =
find_if( myvec.begin(),
myvec.end(),
EqualThruMemFunc<MyVecType,
std::string,
&MyVecType::name>("myname") ) ;


I am sure there is a more elegant solution for a general case. But this
should get you started.

Later,
 
C

Chris \( Val \)

| Hi there,
|
| I found out that very often I use the following construct:
|
| for (it = myvec.begin(); it != myvec.end(); ++it) {
| if (it->name() == "myname")
| break;
| }
|
| Certainly, the container the method and the constant can be of
| any type.
|
| The purpose is to have a template functor and use the
| std::find_if instead of above loop.
| I tried to mix something with std::mem_func and std::equal.
| It looks that this is above my powers.

This could have been simplified with a function object as follows:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

class MatchName
{
private:
std::string ToFind;
public:
template<typename T>
MatchName( const T& Arg ) : ToFind( Arg ) {}

template<typename U>
bool operator() ( const U& Obj ) const
{
return ToFind == Obj.name();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Melvin" ) );

if( std::find_if( V.begin(), V.end(),
MatchName( "Melvin" ) ) != V.end() )
std::cout << "Found " << std::endl;

return 0;
}

Cheers.
Chris Val
 
D

Daniel T.

mikets said:
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

it = find_if(myvec.begin(), myvec.end(),
compose1(bind2nd(equal_to<string>(), "myname"),
mem_fun_ref(&foo::name)));

Note: the above uses the non-standard, but obviously very useful,
unary_compose adaptor. An implementation of which can be found on SGI's
website.

Here is a complete program proving that the above find_if is equivalent
to your origional loop:

/*
* Portions Copyright (c) 1994 Hewlett-Packard Company
* used with permission.
*/


#include <string>
#include <iostream>
#include <vector>
#include <functional>

class foo {
std::string _name;
public:
foo( const std::string& n ): _name( n ) { }
const std::string& name() const { return _name; }
};

template <class _Operation1, class _Operation2>
class unary_compose
: public std::unary_function<typename _Operation2::argument_type,
typename _Operation1::result_type>
{
protected:
_Operation1 _M_fn1;
_Operation2 _M_fn2;
public:
unary_compose(const _Operation1& __x, const _Operation2& __y)
: _M_fn1(__x), _M_fn2(__y) {}
typename _Operation1::result_type
operator()(const typename _Operation2::argument_type& __x) const {
return _M_fn1(_M_fn2(__x));
}
};

template <class _Operation1, class _Operation2>
inline unary_compose<_Operation1,_Operation2>
compose1(const _Operation1& __fn1, const _Operation2& __fn2)
{
return unary_compose<_Operation1,_Operation2>(__fn1, __fn2);
}

int main()
{
using namespace std;
vector<foo> myvec;
myvec.push_back( foo( "joe" ) );
myvec.push_back( foo( "myname" ) );
myvec.push_back( foo( "harold" ) );

vector<foo>::iterator it;
for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}
assert( it->name() == "myname" );

vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
compose1( bind2nd( equal_to<string>(), "myname" ),
mem_fun_ref(&foo::name) ) );
assert( it2 == it );

cout << "OK" << endl;
}
 
M

mikets

Thank you all.

I feel, CrayzeeWulf's suggestion is the most close to what I
need. Definitely, the member method name() was for example only.
In fact, member methods vary also, not necessarily - it may be
also id(), or any other method, with the corresponding value type.

Mike.
 
M

mikets

Thanks, Daniel.

This is great!

Mike.
it = find_if(myvec.begin(), myvec.end(),
compose1(bind2nd(equal_to<string>(), "myname"),
mem_fun_ref(&foo::name)));

Note: the above uses the non-standard, but obviously very useful,
unary_compose adaptor. An implementation of which can be found on SGI's
website.

Here is a complete program proving that the above find_if is equivalent
to your origional loop:

/*
* Portions Copyright (c) 1994 Hewlett-Packard Company
* used with permission.
*/


#include <string>
#include <iostream>
#include <vector>
#include <functional>

class foo {
std::string _name;
public:
foo( const std::string& n ): _name( n ) { }
const std::string& name() const { return _name; }
};

template <class _Operation1, class _Operation2>
class unary_compose
: public std::unary_function<typename _Operation2::argument_type,
typename _Operation1::result_type>
{
protected:
_Operation1 _M_fn1;
_Operation2 _M_fn2;
public:
unary_compose(const _Operation1& __x, const _Operation2& __y)
: _M_fn1(__x), _M_fn2(__y) {}
typename _Operation1::result_type
operator()(const typename _Operation2::argument_type& __x) const {
return _M_fn1(_M_fn2(__x));
}
};

template <class _Operation1, class _Operation2>
inline unary_compose<_Operation1,_Operation2>
compose1(const _Operation1& __fn1, const _Operation2& __fn2)
{
return unary_compose<_Operation1,_Operation2>(__fn1, __fn2);
}

int main()
{
using namespace std;
vector<foo> myvec;
myvec.push_back( foo( "joe" ) );
myvec.push_back( foo( "myname" ) );
myvec.push_back( foo( "harold" ) );

vector<foo>::iterator it;
for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}
assert( it->name() == "myname" );

vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
compose1( bind2nd( equal_to<string>(), "myname" ),
mem_fun_ref(&foo::name) ) );
assert( it2 == it );

cout << "OK" << endl;
}
 
J

Jeff Schwab

Daniel said:
it = find_if(myvec.begin(), myvec.end(),
compose1(bind2nd(equal_to<string>(), "myname"),
mem_fun_ref(&foo::name)));

Note: the above uses the non-standard, but obviously very useful,
unary_compose adaptor. An implementation of which can be found on SGI's
website.

Here is a complete program proving that the above find_if is equivalent
to your origional loop:

/*
* Portions Copyright (c) 1994 Hewlett-Packard Company
* used with permission.
*/


#include <string>
#include <iostream>
#include <vector>
#include <functional>

class foo {
std::string _name;
public:
foo( const std::string& n ): _name( n ) { }
const std::string& name() const { return _name; }
};

template <class _Operation1, class _Operation2>
class unary_compose
: public std::unary_function<typename _Operation2::argument_type,
typename _Operation1::result_type>
{
protected:
_Operation1 _M_fn1;
_Operation2 _M_fn2;
public:
unary_compose(const _Operation1& __x, const _Operation2& __y)
: _M_fn1(__x), _M_fn2(__y) {}
typename _Operation1::result_type
operator()(const typename _Operation2::argument_type& __x) const {
return _M_fn1(_M_fn2(__x));
}
};

template <class _Operation1, class _Operation2>
inline unary_compose<_Operation1,_Operation2>
compose1(const _Operation1& __fn1, const _Operation2& __fn2)
{
return unary_compose<_Operation1,_Operation2>(__fn1, __fn2);
}

int main()
{
using namespace std;
vector<foo> myvec;
myvec.push_back( foo( "joe" ) );
myvec.push_back( foo( "myname" ) );
myvec.push_back( foo( "harold" ) );

vector<foo>::iterator it;
for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}
assert( it->name() == "myname" );

vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
compose1( bind2nd( equal_to<string>(), "myname" ),
mem_fun_ref(&foo::name) ) );
assert( it2 == it );

cout << "OK" << endl;
}

I've been looking for something along those lines. :)
 
C

Chris \( Val \)

| Daniel T. wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) != V.end() )
std::cout << "Working with Chris :) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val
 
C

Cy Edmunds

Chris ( Val ) said:
| Daniel T. wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) != V.end() )
std::cout << "Working with Chris :) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val

Here's the code the OP was trying to avoid:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

My comment is this: none of these proposals, including mine, are worth it!
 
C

Chris \( Val \)

| | >
| > | > | Daniel T. wrote:

[snip]

| > What do you think ? Comments ?
| >
| > Cheers.
| > Chris Val
| >
| >
|
| Here's the code the OP was trying to avoid:
|
| for (it = myvec.begin(); it != myvec.end(); ++it) {
| if (it->name() == "myname")
| break;
| }
|
| My comment is this: none of these proposals, including mine, are worth it!

You know, when you look at it like that, you're
absolutely right - dang library :).

Cheers.
Chris Val
 
J

Jeff Schwab

Cy said:
| Daniel T. wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) !=

V.end() )
std::cout << "Working with Chris :) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val


Here's the code the OP was trying to avoid:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

My comment is this: none of these proposals, including mine, are worth it!

Well, at least that nasty break could be removed. So could the whole
loop body.

for( it = myvec.begin( );
it != myvec.end( ) && it->name( ) != "myname";
++it );
 
M

mikets

I would still consider the template solution.

I didn't bother when I had few similar loops. Now I have about
10 such and most probably there will be more.

So if we don't look into the header, the lines with:

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>
( "Chris", &Person::name ) ) != V.end() )
{
}

still look attractive, while almost don't decrease the number of
source lines.

Mike

Jeff said:
Cy said:
| Daniel T. wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(),
myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) !=


V.end() )
std::cout << "Working with Chris :) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val


Here's the code the OP was trying to avoid:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

My comment is this: none of these proposals, including mine, are worth
it!


Well, at least that nasty break could be removed. So could the whole
loop body.

for( it = myvec.begin( );
it != myvec.end( ) && it->name( ) != "myname";
++it );
 
C

Chris \( Val \)

| I would still consider the template solution.
|
| I didn't bother when I had few similar loops. Now I have about
| 10 such and most probably there will be more.
|
| So if we don't look into the header, the lines with:
|
| if( std::find_if( V.begin(), V.end(),
| MatchName<Person, std::string>
| ( "Chris", &Person::name ) ) != V.end() )
| {
| }
|
| still look attractive, while almost don't decrease the number of
| source lines.

Thanks.

Here is another example that you can play with,
but it does not handle <Person*> at this stage:

template<class Object, class Iter, class Criteria, class Method>
inline Iter Find_If( Iter Pos, Iter EndPos,
const Criteria& Value, Method FuncPtr )
{
for( Pos; Pos != EndPos; ++Pos )
if( (Pos->* FuncPtr)() == Value )
return Pos;

return EndPos;
}

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( Find_If<Person>( V.begin(), V.end(),
"Chris", &Person::name ) != V.end() )
{
std::cout << "Working with Chris :) " << std::endl;
}

Please feel free to play around, and modify it to
suit your needs - I'm sure it can be improved further :).

Cheers.
Chris Val
 
D

Daniel T.

mikets said:
I would still consider the template solution.

I didn't bother when I had few similar loops. Now I have about
10 such and most probably there will be more.

So if we don't look into the header, the lines with:

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>
( "Chris", &Person::name ) ) != V.end() )
{
}

still look attractive, while almost don't decrease the number of
source lines.

You can combine the general usefullness of my solution with the ease of
use of the above solution:

template <typename Object, typename DataType>
inline unary_compose<std::binder2nd<std::equal_to<DataType> >,
std::const_mem_fun_ref_t<const DataType&, Object> >
MatchName(DataType data, const DataType&(Object::*func)() const )
{
using namespace std;
return compose1(bind2nd(equal_to<DataType>(), data),
mem_fun_ref(func));
}

"MatchName" now returns the object necessary to do the job, and is
somewhat easer to use than the above example of yours:

vector<foo>::iterator it2 = find_if( myvec.begin(), myvec.end(),
MatchName( string("myname"), &foo::name ) );

We can generalize that some more and get:

template <typename Func, typename T>
inline unary_compose<std::binder2nd<std::equal_to<T> >, Func >
MatchReturnTo( T data, Func func )
{
using namespace std;
return compose1(bind2nd(equal_to<T>(), data), func);
}

Which would work with any function, function object, member-function, or
pointer to member function that returns the same type that "data" is.
For this example it would be used thus:

vector<foo>::iterator it2 = find_if(myvec.begin(), myvec.end(),
MatchReturnTo(string("myname"), mem_fun_ref(&foo::name)));
 
C

Chris \( Val \)

|
| > I would still consider the template solution.
| >
| > I didn't bother when I had few similar loops. Now I have about
| > 10 such and most probably there will be more.
| >
| > So if we don't look into the header, the lines with:
| >
| > if( std::find_if( V.begin(), V.end(),
| > MatchName<Person, std::string>
| > ( "Chris", &Person::name ) ) != V.end() )
| > {
| > }
| >
| > still look attractive, while almost don't decrease the number of
| > source lines.
|
| You can combine the general usefullness of my solution with the ease of
| use of the above solution:

[ snipped some interesting stuff :),
that I will look into, thanks Daniel ].

Cheers.
Chris Val
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top