Thread: Filling in a table

  1. #1
    Registered User
    Join Date
    May 2008
    Posts
    87

    Filling in a table

    Hi, I'm pondering a design decision (which I find to be the hard part):

    I have a y-by-x table where y and x are passed in by the user, and I'm looking for ideas on how to create a concise constructor that can populate the table. Perhaps with some kind of generic iterator? To be honest, I don't know iterators very well, just started reading through some standard library documentation. Further down the road, this table will be populated with rates that are stored in some external data source. I would like to be flexible on where the data comes from, so I don't want to tie it down to anything too specific. Here's what I'm thinking:

    Code:
    class MyTable {
      private:
        vector<vector<double>> rates;
        int startX, startY;
        ...
    
      public:
        MyTable(int startY, int lenY, int startX, int lenX, double fill = 0);
        MyTable(int startY, int lenY, int startX, int lenX, Itor& it);
        ...
    };
    The first constructor can fill the table in with a constant value. The second constructor is what I am currently pondering. Is there (or can I define) some kind of generic enough pointer or iterator that I can use here without placing too many restrictions on the code that calls the constructor? Or, how would you fill this table? Perhaps introduce a template parameter for the iterator type? Better ideas?

  2. #2
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    How do you want the constructor to be used? Would 'it' be expected to iterate over some one-dimensional set of doubles?

    Or maybe 'it' is an object that overloads operator() so you can initialize for each (x,y)?

    Anyway, you can use a template constructor to allow any type for 'it', and then just use 'it' in a reasonable way.
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  3. #3
    Registered User
    Join Date
    May 2008
    Posts
    87
    If I went the route of using an iterator, then I for simplicity, I think I'll require the iterator to iterate over a 1 dimensional set of doubles. That is, the 1d set spans the entire table, columns stacked on each other. The table is is a fixed row-column rectangle. In the table I'll simplify things a little too, changing
    Code:
    vector<vector<double>> rates;
    to just
    Code:
    vector<double> rates;
    If the numbers of columns change, there is some painful copying/inserting, but that won't be happening often. So, with a template, I think the class would look something like:
    Code:
    class MyTable {
      private:
        vector<double> rates;
        int startX, startY;
        ...
    
      public:
        MyTable(int startY, int lenY, int startX, int lenX, double fill = 0);
        <template class Itor> MyTable(int startY, int lenY, int startX, int lenX, Itor& start, 
                                                               Itor& end);
        ...
    }
    Does the class need to be a template if a member function is?

    Not sure if the iterators should be reference types or not, I'll have to play with it. I guess it wasn't too hard. I've shied away from templates so far while I've been learning c++. I imagine when data access gets implements, I'll be able to define an iterator in such a way that it can iterate over the result set from a SQL query.

  4. #4
    Registered User
    Join Date
    May 2008
    Posts
    87
    Quote Originally Posted by jason_m View Post
    Does the class need to be a template if a member function is?
    I shouldn't post past my bed time. Of course the class would need to be a template too. Otherwise what would the syntax be for calling the constructor? Doubt the compiler would figure it out on the fly.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by jason_m
    Does the class need to be a template if a member function is?
    (...)
    Of course the class would need to be a template too. Otherwise what would the syntax be for calling the constructor? Doubt the compiler would figure it out on the fly.
    Actually, the answer is no. For example:
    Code:
    #include <ostream>
    
    class X
    {
    public:
        explicit X(int a) : a(a) {}
    
        template<typename T>
        void foo(std::ostream& out, const T& b) const
        {
            out << a << " meets " << b << std::endl;
        }
    private:
        int a;
    };
    
    #include <iostream>
    #include <string>
    
    int main()
    {
        using std::cout;
    
        X x(12);
        x.foo(cout, 34);
        x.foo(cout, 56.78);
        x.foo(cout, "a string");
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by jason_m View Post
    I shouldn't post past my bed time. Of course the class would need to be a template too. Otherwise what would the syntax be for calling the constructor? Doubt the compiler would figure it out on the fly.
    No, of course it wouldn't need to.
    The constructor is like a normal function. When you pass in argument to it, it can deduce the type of those arguments.
    OTOH, for a class template, there is no way the compiler can deduce the type.
    Regardless, the standard forces you to specify a type for a class template but not for member functions (only if the compiler can deduce the types).

    Also, it should be...
    template<typename Itor>
    ...and not what you typed.

    And just for another piece of advance. Since this is a table, you're probably going to allow outside access, right? And since it's 2D, the best bet would be a () operator. So all and any access to the contents of the table, either on the inside or outside, is best done via this member operator. Abstraction.
    But then it makes sense that the iterator should overload () as well. Then you can abstract that, as well. How you implement the () operator in the iterator is completely up to you and you can even change it from 1D later if you want. It won't break the code.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    Here's something with a template constructor using an argument like an iterator:
    Code:
    #include <iostream>
    #include <vector>
    #include <string>
    
    class PrintFirstN
    {
       public:
          template<typename iterator_type>
          PrintFirstN(unsigned N, iterator_type it)
          {
             for(unsigned int i = 0; i < N; ++i, it++)
                std::cout << *it << '\n';
          }
    };
    
    int main()
    {
       const char* cstrs[] = {"ah","ajd","223","dkjhf","1234",
                        "head","foot","&^%&*^","!!haha","?"};
       int nums[] = {1,2,3,4,5,6,7,8,9,10};
       std::vector<int> vnums(nums,nums+10);
       std::vector<std::string> cppstrs(cstrs,cstrs+10);
    
       PrintFirstN foo_a(10,cstrs);
       PrintFirstN foo_b(10,nums);
       PrintFirstN foo_c(10,vnums.begin());
       PrintFirstN foo_d(10,cppstrs.begin());
    
       return 0;
    }
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  8. #8
    Registered User
    Join Date
    May 2008
    Posts
    87
    Thank you for all of your replies, you have helped me out a lot. The last thing I am trying to decide is whether I should use two iterators - a begin and an end, or do like CodeMonkey's example, and use one iterator since the number of elements is known.

    In the case of the begin and end, I can verify that the sequence being passed in was in fact the right size. With a single iterator and a size, a situation could happen such as my table is 10 elements long, and the sequence being passed in is only 5 elements long. The former case seems much easier to detect and flag as an error, so I that is the direction I am leaning toward.

    In code, my choices are:
    Code:
    template <typename Itor>
    MyTable(const int startY, const int lenY, const int startX, const int lenX,
                     Itor& start, Itor& end);  /* Check for end of input sequence */
    
    template <typename Itor> 
    MyTable(const int startY, const int lenY, const int startX, const int lenX, 
                     Itor& start);  /* I hope I don't go beyond the end? */

  9. #9
    Registered User
    Join Date
    May 2008
    Posts
    87
    If I break my code up the way I am used to:
    - A header file MyTable.h that only declares member functions
    - An implementation file MyTable.cpp that defines/implements those functions, and
    - A program file test.cpp with main() that uses a MyTable,

    then the linker bugs out, saying the member function is undefined:
    undefined reference to `MyTable::MyTable<double*>(int, int, double*, double*)'
    I think I can understand this - the implementation file was compiled separately from the program source. At the time the implementation file was compiled, the compiler didn't know to create a version of the constructor with double* parameters. My question is: what is common practice to resolve this? Do I need to include the definition of my templated functions in the header? Is there some compiler option (using gcc 4.4.3) I can use?

    Thanks

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You didn't define the template function in an implementation file, did you?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    May 2008
    Posts
    87
    Yes, that being the way I have done things before for non-template functions.

    I found this to be a good write-up on the subject:
    [35] Templates, C++ FAQ Lite

    Looking over the options, I guess I'll throw the definition in the header. It feels messy to me to have part of my class implemented in the header, while the rest of it is implemented in another file, but I might like that option better than including the implementation .cpp file everywhere.

    Out of curiosity, why are compiler vendors pushing back on "extern"? Is it very difficult to implement?

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes, templates are notoriously difficult and the extern keyword even more so.
    You can bet that many compilers have bugs with their template parsing. I have managed to crash my compiler a lot of times with templated code.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by jason_m
    Out of curiosity, why are compiler vendors pushing back on "extern"? Is it very difficult to implement?
    Perhaps you mean export rather than extern? The compiler vendors are about to win the "no export" battle as that feature is expected to be removed from standard C++.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    Registered User
    Join Date
    May 2008
    Posts
    87
    Quote Originally Posted by laserlight View Post
    Perhaps you mean export rather than extern? The compiler vendors are about to win the "no export" battle as that feature is expected to be removed from standard C++.
    Yes, you are correct, I meant export.

  15. #15
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Code:
    MyTable(int startY, int lenY, int startX, int lenX, double fill = 0);
    y-by-x table where y and x...
    The constructor for your table is not a y by x table. If each row can have a variable number of columns then it is not a y by x table.

    I realize I'm joining this a bit late but why all the complexity for just a simple table? I find it extremely non-intuitive to access a table IE: a 2D array in iterator fashion. If all you are doing is wrapping access to a 2D array or a vector of vectors then make the interface simple. What I see is an awful lot of complexity and C++ syntactical sugar for not a lot of benefit in the end. If this is not a simple 2D array or vector of vectors then I would ask what requirement is forcing you to use such a strange data structure?
    Last edited by VirtualAce; 08-14-2010 at 11:54 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Please help me as fast as possible
    By Xbox999 in forum C Programming
    Replies: 5
    Last Post: 11-30-2009, 06:53 PM
  2. help with structs and malloc!
    By coni in forum C Programming
    Replies: 20
    Last Post: 09-14-2009, 05:38 PM
  3. Writing array, to file
    By zootreeves in forum C Programming
    Replies: 9
    Last Post: 09-08-2007, 05:06 PM
  4. extra word printing
    By kashifk in forum C++ Programming
    Replies: 2
    Last Post: 10-25-2003, 04:03 PM
  5. inputting words from a file
    By kashifk in forum C++ Programming
    Replies: 5
    Last Post: 10-24-2003, 07:18 AM