Thread: Problem in template that uses "decltype", "typename", and "std::remove_reference"

  1. #1
    Registered User
    Join Date
    Jul 2014
    Location
    Calgary, Canada
    Posts
    29

    Problem in template that uses "decltype", "typename", and "std::remove_reference"

    Afternoon all,

    I have got a problem here that I cannot get sorted out.

    The attached code runs fine as coded. If, however, you uncomment the alternate return lines 82 and 89 (in UnorderedMap::c0val and UnorderedMap::c1val), compile time errors result.

    This bugs me, because those commented out return lines show the approach I would really prefer to use.

    I have just started learning how to use the new C++11 "decltype" and "std::remove_reference" features in the past few days, so my mistake almost certainly lies at lines 42 to 45, in Sheet::data<I>(), where these are both being used.

    Anyways, here's the code:

    Code:
    #include <tuple>
    #include <unordered_map>
    #include <vector>
    #include <type_traits>
    
    
    #include <cstdio>
    
    
    // Compiler used: gcc version 4.6.3 on Ubuntu, via g++ Typename.C -std=c++0x
    
    
    template<class C0, class C1>
    class Sheet
    {
     public:
    
    
      // Simple "spreadsheet" class with an embedded 2-tuple.
      // Here std::get<0>(embed) is an std::vector<C0>, the "first column",
      //  and std::get<1>(embed) is an std::vector<C1>, the "second column".
    
    
      std::tuple<std::vector<C0>, 
                 std::vector<C1>>   embed;
    
    
      // Template function to return the std::vector::data() pointers of the
      //   C0 and C1 vectors in the embedded object.
      // Since std::get<I>() returns an std::vector<C0 or C1>&, but we want a
      //   (C0*) or (C1*), we need to strip away the reference, and then use
      //   std::vector::value_type to get (C0) or (C1), and add a pointer.
      // I have little experience with "decltype", so this is almost certainly
      //   where the mistake lies.
      // Notice that both std::remove_reference::type and std::vector::value_type
      //   are typenames, but I've got only one "typename" listed here; that
      //   bugs me. (I did try using remove_reference_t, but couldn't figure out
      //   the correct syntax for its use.)
    
    
      template<int I>
      auto data() -> typename std::remove_reference
                              < decltype(std::get<I>(embed))
                              > ::type
                              ::value_type *
      {
        return std::get<I>(embed).data();
      }
    
    
      // Forwarders to the data<I>() template.
      // You'll see in a minute why we need these.
    
    
      C0* c0data() { return data<0>(); }
      C1* c1data() { return data<1>(); }
    };
    
    
    template<class Key, class C0, class C1>
    class UnorderedMap
    {
      // Now, a class with an embedded unordered_map of Keys to Sheet<C0,C1>s.
    
    
     public:
      std::unordered_map<Key, Sheet<C0, C1>> uomap;
    
    
      // These forwarders take a Key argument, and return the data() pointers of
      //   the corresponding Sheet's std::vectors in the embedded unordered_map.
      // PROBLEM pops up at this point:
      // These *only* work when the Sheet::c0data/c1data forwarders are used.
      // Compilation fails if you try to use Sheet::data<I>, with this error:
      // "69:34: error: expected primary-expression before ‘)’ token".
      // Since the only thing Sheet::c0data/c1data do is to call Sheet::data<I>,
      //   I'm at a loss to explain this.
    
    
      C0* c0val(Key key)
      {
      //return uomap.at(key).data<0>(); // Compile time error
        return uomap.at(key).c0data();
      }
    
    
      C1* c1val(Key key)
      {
      //return uomap.at(key).data<1>(); // Compile time error
        return uomap.at(key).c1data();
      }
    };
    
    
    // Test program.
    
    
    int main()
    {
      // Create a simple three-row Sheet<float, double>.
    
    
      Sheet<float,double> s;
      std::get<0>(s.embed) = std::vector<float>  {1., 3., 5.};
      std::get<1>(s.embed) = std::vector<double> {2., 4., 6.};
    
    
      // Print out the addresses of the embedded float and double vectors,
      //   and their first elements (1. and 2.).
    
    
      printf("In original Sheet:\n");
      printf("Vectors are at  %p and %p\n", s.data<0>(),    s.data<1>());
      printf("First values:   %f and %f\n", s.data<0>()[0], s.data<1>()[0]);
    
    
      // Now make up an UnorderedMap whose embedded object contains only one
      //   element: the above-defined Sheet, at integer Key value 3.
    
    
      UnorderedMap<int, float, double> x;
    
    
      x.uomap[3] = s;
    
    
      // Here in main(), there is no problem with using Sheet::data<I>.
    
    
      printf("In UnorderedMap:\n");
      printf("Vectors are at  %p and %p\n", x.uomap[3].data<0>(),    
                                            x.uomap[3].data<1>());
      printf("First  values:  %f and %f\n", x.uomap[3].data<0>()[0], 
                                            x.uomap[3].data<1>()[0]);
      printf("Second values:  %f and %f\n", x.c0val(3)[1],
                                            x.c1val(3)[1]);
    }
    Thanks
    Grump
    Last edited by Grumpulus; 12-08-2014 at 05:12 PM.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Here's your solution: https://stackoverflow.com/questions/...template-class
    Why you do use printf instead of std::cout?
    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.

  3. #3
    Registered User
    Join Date
    Jul 2014
    Location
    Calgary, Canada
    Posts
    29
    You seem to have hit the nail on the head, Elysia. It's working now. Thanks very much.

    This was classic misdirection. I assumed that my mistake had to be in the subject material that I had just learned. But it was actually in the subject material I hadn't learned yet -- namely, the keyword form of "template", which I didn't know existed before now. Remedial reading time.

    Quote Originally Posted by Elysia View Post
    Why you do use printf instead of std::cout?
    That's just an idiosyncrasy. I've known about std::cout for years and years, of course, but for some reason I always end up going back to printf. Apparently the leopard can change only so many of his spots.

    Grump

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Can't get "return()" to work.Problem in "if" part
    By coder1 in forum C Programming
    Replies: 13
    Last Post: 09-10-2013, 01:08 AM
  2. Replies: 2
    Last Post: 08-19-2012, 06:15 AM
  3. Replies: 4
    Last Post: 07-17-2012, 09:02 AM
  4. "itoa"-"_itoa" , "inp"-"_inp", Why some functions have "
    By L.O.K. in forum Windows Programming
    Replies: 5
    Last Post: 12-08-2002, 08:25 AM
  5. "CWnd"-"HWnd","CBitmap"-"HBitmap"...., What is mean by "
    By L.O.K. in forum Windows Programming
    Replies: 2
    Last Post: 12-04-2002, 07:59 AM