Pre-Compile check if field does allready exists

Hello,

im new here and i am searching for a solution for the following problem:

I have a dynamic storage class based on a vector.
The elements of this class shall be addressable via a string.

I have something like the follwing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
StorageClass* test = new StorageClass();

while(notEnd) {

test->setValue("name3", 3);
test->setValue("name2", 4);


...

if (a > 1) {
   test->setValue("name1", 5);
}

...

test->writeLineToFile("filename.csv");

}



The Storage class is implementet with a vector having to attributes per entry, the first one is name the second one is value. If the setValue function is called, Igo through the whole vector to find the correct item via the name and than i set the new value.

At the end of the loop i want to write out the data into a comma seperated value file (*.csv). This shall be done generic by the writeLineToFile() function of the StroageClass.

As a want the columns in csv file to be sorted in a specific way a thought about a preInitalisation routine at the begining of the program which builds a the vector with all possible entrys as something linke this in order to define a specific output order.

1
2
3
test->assign("name1");
test->assign("name2");
test->assign("name3");


So my outputfile should look like this:


name1;name2;name3;
5;4;3;


I now have 2 places in the code where i write down the "fieldnames".

I was wondering if there is a possibility to check if the fields called by the setValue function were first aranged in the vector by the assigned() function before or bettwer while compiling the programm.

I thought about MAKROS with #define XYZ and #ifndef XYZ #error to do though, but currently i reached a dead end and find no solution for my problem.

I hope you understood the problem and a would appreciate any help or even hints how i can solve this problem. If there are any questions please feel free to ask again.

Thanks.
Last edited on
Maybe I don't really understand your job. But at a first hint I would use a map instead of a vector (see http://www.cplusplus.com/reference/map/).
Something along these lines, perhaps (can be more efficient):

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <initializer_list>

const std::vector<std::string> order_of_field_mames { "seven", "two", "five", "one", "four", "six", "three" } ;

struct compare_field_mames
{
    bool operator() ( const std::string& a, const std::string& b ) const
    {
        const auto iter_a = std::find( std::begin(order_of_field_mames), std::end(order_of_field_mames), a ) ;
        const auto iter_b = std::find( std::begin(order_of_field_mames), std::end(order_of_field_mames), b ) ;
        if( iter_a != std::end(order_of_field_mames) || iter_b != std::end(order_of_field_mames) ) // at least one was found
            return iter_a < iter_b ;
        else return a < b ; // nether a nor b was found in the vector
    }
};

struct storage_class
{
    void assign( const std::string& name, int value ) { name_value_pairs[name] = value ; }

    void assign( std::initializer_list< std::pair<std::string,int> > nv_pairs )
    { for( const auto& pair : nv_pairs ) assign( pair.first, pair.second ) ; }

    std::map< std::string, int, compare_field_mames > name_value_pairs ;

    std::ostream& write_lines( std::ostream& stm )
    {
        constexpr char DELIMITER = ';' ;
        for( const auto& pair : name_value_pairs ) stm << pair.first << DELIMITER ;
        stm << '\n' ;
        for( const auto& pair : name_value_pairs ) stm << pair.second << DELIMITER ;
        return stm << '\n' ;
    }
};

int main()
{
    storage_class sc ;
    sc.assign( { { "five", 5 }, { "nine", 9 }, { "four", 4 }, { "zero", 0 }, { "six", 6 }, { "two", 2 } } ) ;
    sc.write_lines(std::cout) ;
}

http://coliru.stacked-crooked.com/a/4bf9317bf1bb2242
This sort of problem was tackled in an old thread.
http://www.cplusplus.com/forum/general/141732/2/

Here was JLBorges' and dhayden's solution:
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
#include <iostream>
#include <string>
#include <random>
#include <ctime>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <unordered_map>
#include <unordered_set>

struct object
{
    std::string id ;
    object( std::string&& name = "" ) : id( std::move(name) ) {}
};

object random_object()
{
    static char alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
    static constexpr std::size_t N = sizeof(alphabet) - 1 ;
    static std::mt19937 twister( std::time(nullptr) ) ;
    static std::uniform_int_distribution<std::size_t> distr( 2, 10 ) ;

    std::shuffle( alphabet, alphabet+N, twister ) ;
    return { { alphabet, alphabet + distr(twister) } } ;
}

int main()
{
    const std::size_t N = 1024 * 128 ;

    std::vector<object> master ;
    while( master.size() < N ) master.push_back( random_object() ) ;
    std::cout << "master size: " << master.size() << '\n' ;

    constexpr int REPEAT = 5 ;
    std::srand( std::time(nullptr) ) ;
    std::vector< object > subset ;
    for( int i = 0 ; i < REPEAT ; ++i )
    {
        // create random subset
        subset.clear() ;
        for( std::size_t j = i ; j < N ; j +=  2 + i*2 ) subset.push_back( master[j] ) ;
        std::random_shuffle( subset.begin(), subset.end() ) ; // rearrange subset

        const auto start = std::clock() ;

        // destructively move subset elements to a hash table
        std::unordered_set<std::string> set ;
        for( object& obj : subset ) set.insert( std::move( obj.id ) ) ;

        std::vector< object > temp ; // scratch area

        // iterate through the master, look up, append to temp
        for( const object& obj : master )
        {
            auto iter = set.find(obj.id) ;
            if( iter != set.end() )
            {
                std::string mvalue = *iter ;
                temp.emplace_back( std::move(mvalue) ) ;
            }
        }

        subset.swap(temp) ; // copy temp to subset, discard subset

        const auto end = std::clock() ;
        std::cout << "subset size: " << subset.size() << ' ' << ( end - start ) / double(CLOCKS_PER_SEC) << " seconds.\n" ;
    }
}

It would appear that JLBorges is following the same idea here (the hash_table is storage_class::name_value_pairs, whose ::key_compare is doing the iterating search through the master), so I think his first try at a solution above already has optimal performance.

If there was an international C++ contest, I would be very interested in seeing what JLBorges' placing in the contest would be.
Last edited on
Thanks for all your replys.
I allready tried out your solutions but they all have a bit of a problem..

I think i did not described my problem very well, so i try once again.

What a need:
- kind of an easy mechanism, because i want to define a "standard" use for other programmers (some with less c++ knowlege)

- a storiage class which i can "address" via string-names

- the possibility to be able to sort the signals as i define by the order of "assigning" the "string"-addess (needed because i want to genarate a

- the possiblility to check if all values which will be written during program exuecutions where assigned to the storage class before.

Problems a am facing with:
- The problem with the <map> mechanism is that i can't define the order.
- I can't check weather the programmer was aware of assigning the "string"-address before he adds a value to this address. The only solution i see is that i check i the object/address exists when a value is written during execution of the program.
- But thats to late, i need a check while copiling the program, somthing like the following
1
2
3
4
5
storage->assign("a");
strorage->assign("b");

storage->setValue("a", 5);
storage->setValue("x", 5);


should result in

Compiler: "x" was never assigned to the storage


I hope it is more clearly now for what i am looking.
Any suggestions on how I can handle this? Are there any possibilitys with the use of MAKROS? I can't figure out a solution.

Thanks for any more help or hints!
Topic archived. No new replies allowed.