Check if that is an string

what I want to do is resolve which on is the biggest member of my object,the object can have any type as It comes from a template...I'm trying to do a function which check is that an string and then use lenght(), and for the rest of the type It can be managed with other ways...but I'm having a troubel detecting is that is a string or not....any help,Thnaks!!!

Basically this is the function which should resolve that...

1
2
3
4
5
6
7
8
9
10
11
 void resolve( ){
		T bigger;
		if(typeid(this->a) == typeid(string())){
			 bigger =  this->a.length() > this->b.length() ? a:b;
			cout<<bigger<<"\n";
		}
		
		bigger =  this->a > this->b ? this->a:this->b;
		cout<<bigger<<"\n";
		
	}
Last edited on
Works for string if you lose the () from string()...

1
2
3
4
5
6
7
8
9
10
    void resolve( ){
        T bigger;
        if(typeid(this->a) == typeid(string)){ // lost the () from string()
            bigger =  this->a.length() > this->b.length() ? this->a : this->b;
            cout<<bigger<<"\n";
        } else { // added else...
            bigger =  this->a > this->b ? this->a : this->b;
            cout<<bigger<<"\n";
        }
    }


But this code will only ever compile for types which have a method length()

Trying with int MSVC gives me the following error:
error C2228: left of '.length' must have class/struct/union

But MyInt class, with a length() method, works ok:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// class templates
#include <iostream>
#include <string>
#include <cmath>
using namespace std;

template<class T>
class myclass{
    T a,b;
public:
    myclass (T x,T y):a(x),b(y){}; 
    
    void resolve( ){
        T bigger;
        if(typeid(this->a) == typeid(string)){ // lost the () from string()
            bigger =  this->a.length() > this->b.length() ? this->a : this->b;
            cout<<bigger<<"\n";
        } else { // added else...
            bigger =  this->a > this->b ? this->a : this->b;
            cout<<bigger<<"\n";
        }
    }
};

class MyInt
{
private:
    int value;
public:
    MyInt() : value(0) {}
    MyInt(int i) : value(i) {}
    MyInt(const MyInt& i) : value(i.value) {}
    operator int() const { return value; };
    // etc.
    int length() const {
        return (value > 0) ? static_cast<int>(log10(static_cast<double>(value))) : -1;
    }
};

int main(){
    //myclass<int> myobjectint(30,25);
    myclass<string> myobjectstring("malaga", "granada");
    myclass<MyInt> myobjectMyInt(123, 1234);
    //myobjectint.resolve();
    myobjectstring.resolve();
    myobjectMyInt.resolve();
    return 0;
}


I could give you a solution, but as this site is about finding things out for yourself, instead I'll point you at std::set for inspiration?
http://www.cplusplus.com/reference/set/set/

Andy

PS Code borrowed from this thread (plus repairs, etc)

Can not resolve overloaded on template
http://www.cplusplus.com/forum/beginner/166251/
Last edited on
But when I was using this It was working...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   
class myclass{
	T a,b;
	
public:
	
	myclass (T x,T y):a(x),b(y){}; 
	
	void resolve( ){
		T bigger;
		bigger =  this->a > this->b ? this->a:this->b;
		cout<<bigger<<"\n";
		
	}
	
	void resolvestring(){
		T bigger = this->a.length() > this->b.length() ? a:b;
		cout<<bigger<<"\n";;
		
		
	}
};


I cant see the difference....if I set an if it would just get into the part where lenght() is because the objcet is composed by two string, any other case It will go to the other part of the function....
But when I was using this It was working...

I guess that's because you didn't try calling resolvestring() on a myclass<int> so the compiler didn't bother to try and generate the int version of the function.

Andy
this is my whole code, when the modification of () in the typeid, and It's not working yet....You said that It was working with you...maybe the problem is not in the part I posted...here is my code, and tomorrow I'll have a look on you have posted properly...tomorrow I have to work unfortunately,ehehehehe...and thanks you, I can learn more when somebody suggest something than when they give to you the solution...I'm learning and that is the way...I post my whole code here...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

// class templates
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;

template<class T>
class myclass{
	T a,b;
	
public:
	
	myclass (T x,T y):a(x),b(y){}; 
	
	 void resolve( ){
        T bigger;
        if(typeid(this->a) == typeid(string)){ // lost the () from string()
            bigger =  this->a.length() > this->b.length() ? this->a : this->b;
            cout<<bigger<<"\n";
        } else { // added else...
            bigger =  this->a > this->b ? this->a : this->b;
            cout<<bigger<<"\n";
        }
    }
	
};	

int main(){

	myclass<int> myobjectint(30,25);
	myclass<float> myobjectfloat(30.23,30.56);
	myclass<string> myobjectstring("malaga","jaen");
	char a = 'a';
	char b = 'a';
	myclass<char> myobjectchar(a,b);
	myobjectint.resolve();
	myobjectfloat.resolve();
	myobjectstring.resolve();
	myobjectchar.resolve();
	
	return 0;
}

C++ is statically typed; strongly favour a compile-time mechanism over a run-time mechanism for this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <string>
#include <cstring>

template < typename T > class myclass {

    T a, b;

    static std::string bigger( const std::string& a, const std::string& b ) { // overload for strings
        return a.length() > b.length() ? a : b ; }

    static const char* bigger( const char* a, const char* b ) { // overload for const c-strings
        auto alen = a ? std::strlen(a) : 0 ;
        auto blen = b ? std::strlen(b) : 0 ;
        return alen > blen ? a : b ;
    }

    static char* bigger( char* a, char* b ) { // overload for c-strings
        auto alen = a ? std::strlen(a) : 0 ;
        auto blen = b ? std::strlen(b) : 0 ;
        return alen > blen ? a : b ;
    }

    template < typename U > static U bigger( const U& a, const U& b ) { // overload for other types
        return a > b ? a : b ; }

    public:
        myclass( const T& x, const T& y ) : a(x), b(y) {}

        void resolve() const {
            std::cout << "bigger( " << a << ", " << b << " ) is: " << bigger(a,b) << '\n' ; }
};

int main(){

    myclass<int>(30,25).resolve() ;
    myclass<float>(30.23,30.56).resolve() ;

    const char c[] = "malaga" ;
    char d[] = "jaen" ;
    myclass<std::string>(c,d).resolve() ;
    myclass<const char*>(c,d).resolve() ;

    char e[] = "jaenn" ;
    myclass<std::string>(d,e).resolve() ;
    myclass<char*>(d,e).resolve() ;
}

http://coliru.stacked-crooked.com/a/ecd8a1af509dd237
You said that It was working with you...

Not with int -- only with my special "MyInt" class, which has a length() method.

JLBorges solution is more or less the one I was attempting to nudge you towards, though with a slight variation. And I see ne555 has also given you another similar solution (still a bit different to the one I'm thinking about) in another of your threads on this topic:

resolve which one is the biggest string
http://www.cplusplus.com/forum/general/166252/#msg837578

Can you see why the solution which don't use the typeid make more sense, even if you could get you code to compile? i.e. do you get JLBorges 's comment above about compile-time versus run-time mechanisms?

Andy
Last edited on
well, I understand that his version is more robust with the meaning that whatever it gets It will be resolved, but I dont know what he means about compile time mechanism and run time mechanism to be honest...I need to be more literate in C++ and read a lot...and about your frist example.....I have undertood perfectly why It wont work in my case because int,double and char they dont have the method lenght(), It just belong to string...but I have still a doubt about that...Once you get into the if( I mean in my code) the lenght() method will just be used when the object is an string, so for tjat reason I'm still confuse.....

and I have undertood what you do with your code, but I get lost with the casting...I know It's a conversion between type...but I'm not sure at all how It's working...

And about set container...that is good solution because the type is the size, and It thas a comp() method, but I guess I should use more than one set...or could I use just one set container for any type....

King Regards.
Maybe this is the reason JLBorges wrote about compile-time mechanism:

static_cast can perform conversions between pointers to related classes, not only upcasts (from pointer-to-derived to pointer-to-base), but also downcasts (from pointer-to-base to pointer-to-derived). No checks are performed during runtime to guarantee that the object being converted is in fact a full object of the destination type. Therefore, it is up to the programmer to ensure that the conversion is safe.
The runtime mechanism in this case is Run-Time Type Information (RTTI), as obtained by the typeid keyword. You're mixing it up with templates in a unusual way when a more appropriate compile time mechanism is available. There's no need for a cast and therefore no need to worry about unsafe conversions. And no need to pay the performance cost of obtaining the type information, either.

This version is pretty much a mixture of ne555's and JLBorges' two suggestions. It was the use of the Compare predicate that led me to point you at std::set as a possible role model (string does the same kind of thing but it's buried a bit deeper in the code.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// class templates
#include <iostream>
#include <string>
#include <cstring>
using namespace std;

template<typename T> // template handles any type which don't have a specialization
class bigger {
public:
    bool operator()(const T& lhs, const T& rhs) const {
        return lhs > rhs;
    }
};

template<class T, class Compare=bigger<T>>
class myclass{
    T a,b;

public:
    myclass (T x,T y):a(x),b(y){}; 

    T resolve( ){
        T bigger;
        bigger = Compare()(this->a, this->b) ? this->a : this->b;
        cout<<bigger<<"\n";
        return bigger;
    }
};

template<>
class bigger<const string&> { // template specialization for const string&
public:
    bool operator()(const string& lhs, const string& rhs) const {
        return (lhs.length() > rhs.length());
    }
};

template<>
class bigger<const char*> { // template specialization for const char*
public:
    bool operator()(const char* lhs, const char* rhs) const {
        size_t lhs_len = lhs ? std::strlen(lhs) : 0 ;
        size_t rhs_len = rhs ? std::strlen(rhs) : 0 ;
        return (lhs_len > rhs_len);   
   }
};

// etc

int main(){
    myclass<int> myobjectint(30,25);
    myclass<float> myobjectfloat(30.23f,30.56f);
    myclass<string> myobjectstring("malaga","granada");
    myclass<const char*> myobjectconstcharstar("cordoba","leon");
    // etc
    myobjectint.resolve();
    myobjectfloat.resolve();
    myobjectstring.resolve();
    myobjectconstcharstar.resolve();
    // etc
    return 0;
}


Andy
Last edited on
yes, in fact I did a version with an especification, but your seems more accurate...this is what I did...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <string>

using namespace std;

template < class T>
class myclass{
	private : 
		T a,b;
	public:
		myclass (const T& x,const T& y): a(x),b(y){};
		 void resolve (){
			T biggest;
			cout<<"The biggest one is:"<<"\n";
			biggest = this->a > this-> b ? a:b;
			cout<<biggest<<"\n";
			
		}
};

template< >
class myclass<char>{
	private:
		char a,b;
	public:
		myclass(const char& x,const char& y): a(x),b(y){};
		void resolve (){
			
			if ( (a or b ) == ('a'or'e' or 'i' or 'o' or 'u')){
				a = 'z';
				b = 'z';
				cout<<"\n";
			}
			else{
				
				cout<<this->a<<" "<<this->b<<" "<<"\n";
			}
			cout<<this->a<<" "<<this->b<<" "<<"\n";
		}
		
};

template< >
	class myclass<string>{
	private:
		string a,b;
	public:
		myclass(const string& x,const string& y): a(x),b(y){};
			
		void resolve(){
			string longer; 
			longer =  this->a.length() > this->b.length() ? this->a : this->b;
            cout<<longer<<"\n";
		}
	};


int main(int argc, char **argv)
{
	myclass<int> myint(12,15);
	myclass<double> mydouble(12.35,45.56);
	myclass<char> mychar('a','b');
	myclass<string> mystring("malaga","cadiz");
	myint.resolve();
	mystring.resolve();
	mydouble.resolve();
	mychar.resolve();
	
	
}


About your cody there is a part which I haven't seen before It's this...
1
2
3

template<class T, class Compare=bigger<T>>



I didnt know that you could set a method (compare in this case) like you could put a variable which usually is called T....and therefore I would have used this expresion compare(bigger T) which make more sense for me..., thiking that compare() must return a type, but It must have an argument to return something...
In the above example, Compare is a Callable type. An object of this type is referred to as a callable object or function object. A function object is any object for which the function call operator is defined.
For instance, std::plus<int>() http://en.cppreference.com/w/cpp/utility/functional/plus

The is no one right design; a viable solution depends on the design intent. For instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>
#include <string>
#include <algorithm>

namespace detail
{
    struct bigger_value
    {
        template < typename T >
        T operator() ( const T& a, const T& b ) const { return a > b ? a : b ; }

    };

    struct bigger_size
    {
        template < typename T >
        T operator() ( const T& a, const T& b ) const { return a.size() > b.size() ? a : b ; }
    };
}

namespace A // implementor (and not the user) specifies the resolve policy
            // resolve policy is an encapsulated implementation detail
{
    template < typename T > class myclass {

        T a, b;

        static std::string bigger( const std::string& a, const std::string& b ) { // overload for strings
            return detail::bigger_size()(a,b) ; }

        template < typename U > static U bigger( const U& a, const U& b ) { // overload for other types
            return detail::bigger_value()(a,b) ; ; }

        public:
            myclass( const T& x, const T& y ) : a(x), b(y) {}

            T resolve() const { return bigger(a,b) ; }
    };
}

namespace B // policy parameterisation: the user can specify the resolve policy,
            // once, right at the beginning, when the type is specified
{
    template < typename T, typename BIGGER = detail::bigger_value > class myclass {

        T a, b;
        BIGGER bigger ; // make a copy; the policy object can have state

        public:
            // accept a policy object; it need not be default-constructible
            myclass( const T& x, const T& y, const BIGGER& cmp = BIGGER() ) : a(x), b(y), bigger(cmp) {}

            T resolve() const { return bigger(a,b) ; }
    };
}

namespace C // the user can specify the resolve policy, each time resolve is to be called
{
    template < typename T > class myclass {

        T a, b;

        public:
            myclass( const T& x, const T& y ) : a(x), b(y) {}

            T resolve() const { return std::max(a,b) ; }

            template < typename BIGGER > T resolve( const BIGGER& bigger = BIGGER() ) const {
                return bigger(a,b) ; }
    };
}

#define RESOLVE(a) ( std::cout << #a << ".resolve(): " << (a).resolve() << "\n\n" )

int main(){

    RESOLVE( A::myclass<int>(30,25) ) ;
    RESOLVE( A::myclass<std::string>( "malaga", "jaennnn" ) ) ;
    std::cout << "-------------------------\n\n" ;

    RESOLVE( B::myclass<int>(30,25) ) ;
    RESOLVE( B::myclass<std::string>( "malaga", "jaennnn" ) ) ;
    RESOLVE( ( B::myclass< std::string, detail::bigger_size >( "malaga", "jaennnn" ) ) ) ;
    std::cout << "-------------------------\n\n" ;

    RESOLVE( C::myclass<int>(30,25) ) ;
    std::cout << "C::myclass<int>(30,25).resolve( [] ( int a, int b ) { return a%10 > b%10 ? a : b ; } ): "
              << C::myclass<int>(30,25).resolve( [] ( int a, int b ) { return a%10 > b%10 ? a : b ; } ) << "\n\n" ;

    C::myclass<std::string> mc( "malaga", "jaennnn" );
    RESOLVE(mc) ;
    std::cout << "mc.resolve<detail::bigger_size>(): " << mc.resolve<detail::bigger_size>() << "\n\n" ;
    std::cout << "mc.resolve( detail::bigger_size() ): " << mc.resolve( detail::bigger_size() ) << "\n\n" ;
}

http://coliru.stacked-crooked.com/a/3854e22d009499ef
And there are alternative techniques to realise the same goal as one of the above.
thank you, I have understood what you mean and I have had to deal with things that I knew just some features as namespace and static...but I having troubles in namespaceB and namespaceC....here..
1
2
3
4
5
6
7
//namespaceB

....const BIGGER& cmp = BIGGER() )

//namespaceC

.....( const BIGGER& bigger = BIGGER() )


in namespaceB i cant see a logic, but I cant see the real relation...I know that the namespace detail is used to call bigger_value where the operator () is overloaded,in here const BIGGER& cmp = BIGGER() ) It should be giving a type, but (the cmp type) but in fact () returns an object type T, which makes senses but not in the declaration of the class....

in namespaceC happens to me the same but without the operator ()overloaded clue...

I think It's the same thing I dont reach to understand in Andy's code...It seems I got work to do this weekend...thank you!!
In const BIGGER& cmp = BIGGER(), BIGGER is a type, not an object.

Where T is a type, T() ( or T{} ) represents an anonymous, value-initialised temporary object of type T.
http://en.cppreference.com/w/cpp/language/value_initialization
T{}: http://www.stroustrup.com/C++11FAQ.html#uniform-init

In
1
2
TYPE foo( TYPE variable = TYPE() ) ; 
foo() ; // use default argument 

the parameter variable is initialised with its default value: an anonymous, value-initialised object of type TYPE


1
2
3
4
BIGGER cmp ; // cmp is a default-initialised object of type BIGGER
BIGGER cmp2 = BIGGER() ; // cmp2 is copy-initialised from an anonymous, value-initialised object of type BIGGER
cmp() ; // cmp is a (callable) object
BIGGER() ; // BIGGER is a type, not an object 
Topic archived. No new replies allowed.