Explicit Casting for Templated Function

I have a project in which I'm including a templated function. The function is supposed to search for and display objects based on a variety of the class' fields. The problem is that I'm uncertain how to ensure that improper usage is caught and handled by the program. So far my code is as follows:

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
template <class T>
void findIn(T d, ArrayList<Planet>& db, char par)
{
    ArrayList<Planet*> trn = ArrayList<Planet*>;

    try
    {
        if(par == 'n')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getName() == (char) d)
                    trn.append(&(db[i]));
            }
        }
        else if(par == 'm')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getMSINI() == (float) d)
                    trn.append(&(db[i]));
            }
        }
        else if(par == 'a')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getAxis() == (float) d)
                    trn.append(&(db[i]));
            }
        }
        else if(par == 'p')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getPer() == (float) d)
                    trn.append(&(db[i]));
            }
        }
        else if(par == 'e')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getEcc() == (float) d)
                    trn.append(&(db[i]));
            }
        }
        else if(par == 'o')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getOm() == (float) d)
                    trn.append(&(db[i]));
            }
        }
        else if(par == 't')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getT0() == (float) d)
                    trn.append(&(db[i]));
            }
        }
        else if(par == 'k')
        {
            for(int i = 0; i < db.getSize(); i++)
            {
                if(db[i].getK() == (float) d)
                    trn.append(&(db[i]));
            }
        }
    }
    catch(bad_cast)
    {
        throw Invalid_Input();
    }

    if(trn.isEmpty())
        cout << "No planets found matching the specified property." << endl;
    else
    {
        for(int i = 0; i < trn.getSize(); i++)
            cout << *(trn[i]) << endl;
    }
}


Am I using the right keywords and looking for the right exception? If not, what should I by trying to catch instead?
Last edited on
What code do you believe throws a std::bad_cast exception? I don't see any code in your try block that would obviously throw an exception you need to handle.

(Also, you should catch exceptions by reference to avoid slicing.)
I don't see any code in your try block that would obviously throw an exception you need to handle.

I'm not even sure that std::bad_cast is the right exception to throw, since the explanation of type casting I found was a bit vague/unintelligible, but beyond that, let's assume that the user accidentally entered 3.1415, pdb, 'n', as the parameters for the function. How should the program handle an input error like that?

Also, you should catch exceptions by reference to avoid slicing.

Please enlighten me on what slicing is and how to catch exceptions by reference?
Maybe this will help:
If char is passed as first argument, get_data(char d overload is selected and any value of par other than "n" will make it throw an exception.
If float is passed as parameter, get_data(float d overload is selected and anything not in the list of foat parameter will lead to exception.
If any other type will be passed, template overload will be selected and exception will be thrown in runtime.

Ways to improve: make non-char-non-float types emit compile-time error (by using static assert or SFINAE).
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
template <class T>
ArrayList<Planet*> get_data(T d, ArrayList<Planet>& db, char par)
{
    throw Invalid_Input();
}

ArrayList<Planet*> get_data(char d, ArrayList<Planet>& db, char par)
{
    ArrayList<Planet*> trn;
    if(par != 'n') throw Invalid_Input();
    for(int i = 0; i < db.getSize(); ++i)
        if(db[i].getName() == d)
            trn.append(&(db[i]));
    retrun trn;
}

ArrayList<Planet*> get_data(float d, ArrayList<Planet>& db, char par)
{
    using member = float (ArrayList<Planet>::*)();
    static member functions[] {
        &ArrayList<Planet>::getMSINI, &ArrayList<Planet>::getAxis,
        &ArrayList<Planet>::getPer,   &ArrayList<Planet>::getEcc,
        &ArrayList<Planet>::getOm,    &ArrayList<Planet>::getT0,
        &ArrayList<Planet>::getK,
    };
    member fun;
    switch(par) {
        case 'm': fun = functions[0]; break;
        case 'a': fun = functions[1]; break;
        case 'p': fun = functions[2]; break;
        case 'e': fun = functions[3]; break;
        case 'o': fun = functions[4]; break;
        case 't': fun = functions[5]; break;
        case 'k': fun = functions[6]; break;
        default: throw Invalid_Input();
    }
    ArrayList<Planet*> trn;
        for(int i = 0; i < db.getSize(); ++i)
            if((db[i].*fun)() == d)
                trn.append(&(db[i]));
    retrun trn;
}

template <class T>
void findIn(T d, ArrayList<Planet>& db, char par)
{
    ArrayList<Planet*> trn = get_data(d, db, par);
    if(trn.isEmpty())
        cout << "No planets found matching the specified property." << endl;
    else
        for(int i = 0; i < trn.getSize(); i++)
            cout << *(trn[i]) << endl;
}


Thank you Mr. Over-achiever, but I don't think that sharing code will be acceptable for this project. Could I just get a name for an exception that gets thrown when an explicit cast fails?
closed account (48T7M4Gy)
Thank you Mr. Over-achiever

That's a bit cruel.
closed account (48T7M4Gy)
Could I just get a name for an exception that gets thrown when an explicit cast fails?

http://lmgtfy.com/?q=Could+I+just+get+a+name+for+an+exception+that+gets+thrown+when+an+explicit+cast+fails%3F
There is no exception with casts. (There is only for dynamic casts, which cannot be used here). It is either a compile-time error (if cast cannot be done at all, e.g. std::string to std::list<int>), or cast with possible loss of data (all arithmetic: char, int, long, float, double... — all of them can be cast to each other), e.g. double 1.23 cast to char '0x01'.

Any your casts are c-style casts which can allow even casts which normaly are impossible: they also work as const cast and reinterpret cast.

You can manually check typeid of T and compare to typeid of char/float if you want runtime behavior, or make a helper function like that:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <type_traits>
#include <iostream>

template <typename T, typename U>
U& assert_type(U& u) {
    if(!std::is_same<T, U>::value) throw u;
    return u;
}

template <typename T>
void foo(T t, char p)
{
    if(p == 'a')
        std::cout << assert_type<char>(t);
    if(p == 'b')
        std::cout << assert_type<int>(t);
}

int main()
{
    foo('w', 'a');
    foo(2, 'b');
    foo(2, 'a'); //Runtime error
}

@kemort: why don't you check if your example really shows that information can be found with such search request before posting?
Last edited on
> The problem is that I'm uncertain how to ensure that improper usage is caught and handled by the program.

Use an enumeration, perhaps; catch as many errors as possible at compile time.

If an exception must be thrown for invalid input, throw std::domain_error
It may be used by the implementation to report domain errors, that is, situations where the inputs are outside of the domain on which an operation is defined. http://en.cppreference.com/w/cpp/error/domain_error

Something like:
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
#include <iostream>
#include <stdexcept>

struct planet
{
    enum property_tag { NAME, MASS, AXIS, /* ... */ /* INVALID */ } ;

    static property_tag char_to_tag( char c )
    {
        switch(c)
        {
            case 'n' : case 'N' : return NAME ;
            case 'm' : case 'M' : return MASS ;
            case 'a' : case 'A' : return AXIS ;
            // ...
            
            default: throw std::domain_error( "invalid property") ; // if exception is to be used
                     // return INVALID ; // otherwise
        }
    }

    // ...
};

template < typename CONTAINER, typename T >
void display_query_results( const CONTAINER& container_of_planets, const T& property_value, planet::property_tag tag ) ;

template < typename CONTAINER, typename T >
void display_query_results( const CONTAINER& container_of_planets, const T& property_value, char par )
{
    display_query_results( container_of_planets, property_value, planet::char_to_tag(par) ) ; // use exception

    // otherwise
    // const auto tag = planet::char_to_tag(par) ;
    // if( tag == planet::INVALID ) { /* error: display an appropriate error message */  }
    // else display_query_results( container_of_planets, property_value, planet::char_to_tag(par) ) ;
}
closed account (48T7M4Gy)
@kemort: why don't you check if your example really shows that information can be found with such search request before posting?


I did and it does.
http://puu.sh/kOwGf/f27a46175a.png
C# C# C# C# PHP Java... Not a single C++ source. All of them with low relevance to boot. Even if there would happen to be C++ source, there is a great chance that it would not be one we need. An "exception when cast fails C++" would work better.
closed account (48T7M4Gy)
Even if ...

Yawn, mere shadow boxing.
Topic archived. No new replies allowed.