Thread: Tuples not working

  1. #1
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445

    Tuples not working

    I have the following code:
    Code:
    #include <string>
    #include <vector>
    #include <tuple>
    
    void ConvertString(const std::string& str, std::string& target)
    {
      target = str;
    }
    
    void ConvertString(const std::string& str, double& target)
    {
      target = std::stod(str);
    }
    
    void ConvertString(const std::string& str, float& target)
    {
      target = std::stof(str);
    }
    
    void ConvertString(const std::string& str, int& target)
    {
      target = std::stoi(str);
    }
    
    void ConvertString(const std::string& str, unsigned int& target)
    {
      target = std::stoul(str);
    }
    
    void ConvertString(const std::string& str, long& target)
    {
      target = std::stol(str);
    }
    
    void ConvertString(const std::string& str, unsigned long& target)
    {
      target = std::stoul(str);
    }
    
    template <size_t Column, typename... Args>
    void ParseDbRowTuple(const std::vector<std::string>& row, std::tuple<Args...>& tuple)
    {
      if (Column >= std::tuple_size<std::tuple<Args...> >::value) return;
    
      ConvertString(row[Column], std::get<Column>(tuple));
    
      ParseDbRowTuple<Column + 1>(row, tuple);
    }
    
    template <typename... Args>
    void ParseDbRowTuple(const std::vector<std::string>& row, std::tuple<Args...>& tuple)
    {
      if (std::tuple_size<std::tuple<Args...> >::value > row.size()) return;
    
      ConvertString(row[0], std::get<0>(tuple));
    
      ParseDbRowTuple<1>(row, tuple);
    }
    
    int main()
    {
      std::vector<std::string> strVec = {"1", "3.14", "foo"};
      std::tuple<int, double, std::string> tuple;
    
      ParseDbRowTuple(strVec, tuple);
    
      return 0;
    }
    and I'm getting the following errors:
    Code:
    $ g++-5 -std=c++14 -o tupleTest tupleTest.cpp
    In file included from tupleTest.cpp:4:0:
    /usr/include/c++/5/tuple: In instantiation of ‘struct std::tuple_element<1ul, std::tuple<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >’:
    /usr/include/c++/5/tuple:755:12:   recursively required from ‘struct std::tuple_element<2ul, std::tuple<double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >’
    /usr/include/c++/5/tuple:755:12:   required from ‘struct std::tuple_element<3ul, std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >’
    /usr/include/c++/5/tuple:769:69:   required by substitution of ‘template<long unsigned int __i, class _Tp> using __tuple_element_t = typename std::tuple_element::type [with long unsigned int __i = 3ul; _Tp = std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]’
    /usr/include/c++/5/tuple:844:5:   required by substitution of ‘template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_Elements ...> >&& std::get(std::tuple<_Elements ...>&&) [with long unsigned int __i = 3ul; _Elements = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
    tupleTest.cpp:48:30:   recursively required from ‘void ParseDbRowTuple(std::vector<std::basic_string<char> >&, std::tuple<_Elements ...>&) [with long unsigned int Column = 2ul; Args = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
    tupleTest.cpp:48:30:   required from ‘void ParseDbRowTuple(std::vector<std::basic_string<char> >&, std::tuple<_Elements ...>&) [with long unsigned int Column = 1ul; Args = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
    tupleTest.cpp:58:21:   required from ‘void ParseDbRowTuple(std::vector<std::basic_string<char> >&, std::tuple<_Elements ...>&) [with Args = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
    tupleTest.cpp:66:32:   required from here
    /usr/include/c++/5/tuple:755:12: error: invalid use of incomplete type ‘struct std::tuple_element<0ul, std::tuple<> >’
         struct tuple_element<__i, tuple<_Head, _Tail...> >
                ^
    In file included from /usr/include/c++/5/tuple:38:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/utility:85:11: note: declaration of ‘struct std::tuple_element<0ul, std::tuple<> >’
         class tuple_element;
               ^
    tupleTest.cpp: In instantiation of ‘void ParseDbRowTuple(std::vector<std::basic_string<char> >&, std::tuple<_Elements ...>&) [with long unsigned int Column = 3ul; Args = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’:
    tupleTest.cpp:48:30:   recursively required from ‘void ParseDbRowTuple(std::vector<std::basic_string<char> >&, std::tuple<_Elements ...>&) [with long unsigned int Column = 2ul; Args = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
    tupleTest.cpp:48:30:   required from ‘void ParseDbRowTuple(std::vector<std::basic_string<char> >&, std::tuple<_Elements ...>&) [with long unsigned int Column = 1ul; Args = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
    tupleTest.cpp:58:21:   required from ‘void ParseDbRowTuple(std::vector<std::basic_string<char> >&, std::tuple<_Elements ...>&) [with Args = {int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
    tupleTest.cpp:66:32:   required from here
    tupleTest.cpp:46:46: error: no matching function for call to ‘get(std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)’
       ConvertString(row[Column], std::get<Column>(tuple));
                                                  ^
    In file included from /usr/include/c++/5/tuple:38:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/utility:147:5: note: candidate: template<long unsigned int _Int, class _Tp1, class _Tp2> constexpr typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)
         get(std::pair<_Tp1, _Tp2>& __in) noexcept
         ^
    /usr/include/c++/5/utility:147:5: note:   template argument deduction/substitution failed:
    tupleTest.cpp:46:46: note:   ‘std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’ is not derived from ‘std::pair<_Tp1, _Tp2>’
       ConvertString(row[Column], std::get<Column>(tuple));
                                                  ^
    In file included from /usr/include/c++/5/tuple:38:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/utility:152:5: note: candidate: template<long unsigned int _Int, class _Tp1, class _Tp2> constexpr typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type&& std::get(std::pair<_Tp1, _Tp2>&&)
         get(std::pair<_Tp1, _Tp2>&& __in) noexcept
         ^
    /usr/include/c++/5/utility:152:5: note:   template argument deduction/substitution failed:
    tupleTest.cpp:46:46: note:   ‘std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’ is not derived from ‘std::pair<_Tp1, _Tp2>’
       ConvertString(row[Column], std::get<Column>(tuple));
                                                  ^
    In file included from /usr/include/c++/5/tuple:38:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/utility:157:5: note: candidate: template<long unsigned int _Int, class _Tp1, class _Tp2> constexpr const typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(const std::pair<_Tp1, _Tp2>&)
         get(const std::pair<_Tp1, _Tp2>& __in) noexcept
         ^
    /usr/include/c++/5/utility:157:5: note:   template argument deduction/substitution failed:
    tupleTest.cpp:46:46: note:   ‘std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’ is not derived from ‘const std::pair<_Tp1, _Tp2>’
       ConvertString(row[Column], std::get<Column>(tuple));
                                                  ^
    In file included from /usr/include/c++/5/tuple:38:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/utility:166:5: note: candidate: template<class _Tp, class _Up> constexpr _Tp& std::get(std::pair<_T1, _T2>&)
         get(pair<_Tp, _Up>& __p) noexcept
         ^
    /usr/include/c++/5/utility:166:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/utility:171:5: note: candidate: template<class _Tp, class _Up> constexpr const _Tp& std::get(const std::pair<_T1, _T2>&)
         get(const pair<_Tp, _Up>& __p) noexcept
         ^
    /usr/include/c++/5/utility:171:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/utility:176:5: note: candidate: template<class _Tp, class _Up> constexpr _Tp&& std::get(std::pair<_T1, _T2>&&)
         get(pair<_Tp, _Up>&& __p) noexcept
         ^
    /usr/include/c++/5/utility:176:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/utility:181:5: note: candidate: template<class _Tp, class _Up> constexpr _Tp& std::get(std::pair<_Up, _Tp>&)
         get(pair<_Up, _Tp>& __p) noexcept
         ^
    /usr/include/c++/5/utility:181:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/utility:186:5: note: candidate: template<class _Tp, class _Up> constexpr const _Tp& std::get(const std::pair<_Up, _Tp>&)
         get(const pair<_Up, _Tp>& __p) noexcept
         ^
    /usr/include/c++/5/utility:186:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/utility:191:5: note: candidate: template<class _Tp, class _Up> constexpr _Tp&& std::get(std::pair<_Up, _Tp>&&)
         get(pair<_Up, _Tp>&& __p) noexcept
         ^
    /usr/include/c++/5/utility:191:5: note:   template argument deduction/substitution failed:
    In file included from /usr/include/c++/5/tuple:39:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/array:280:5: note: candidate: template<long unsigned int _Int, class _Tp, long unsigned int _Nm> constexpr _Tp& std::get(std::array<_Tp, _Nm>&)
         get(array<_Tp, _Nm>& __arr) noexcept
         ^
    /usr/include/c++/5/array:280:5: note:   template argument deduction/substitution failed:
    tupleTest.cpp:46:46: note:   ‘std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’ is not derived from ‘std::array<_Tp, _Nm>’
       ConvertString(row[Column], std::get<Column>(tuple));
                                                  ^
    In file included from /usr/include/c++/5/tuple:39:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/array:289:5: note: candidate: template<long unsigned int _Int, class _Tp, long unsigned int _Nm> constexpr _Tp&& std::get(std::array<_Tp, _Nm>&&)
         get(array<_Tp, _Nm>&& __arr) noexcept
         ^
    /usr/include/c++/5/array:289:5: note:   template argument deduction/substitution failed:
    tupleTest.cpp:46:46: note:   ‘std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’ is not derived from ‘std::array<_Tp, _Nm>’
       ConvertString(row[Column], std::get<Column>(tuple));
                                                  ^
    In file included from /usr/include/c++/5/tuple:39:0,
                     from tupleTest.cpp:4:
    /usr/include/c++/5/array:297:5: note: candidate: template<long unsigned int _Int, class _Tp, long unsigned int _Nm> constexpr const _Tp& std::get(const std::array<_Tp, _Nm>&)
         get(const array<_Tp, _Nm>& __arr) noexcept
         ^
    /usr/include/c++/5/array:297:5: note:   template argument deduction/substitution failed:
    tupleTest.cpp:46:46: note:   ‘std::tuple<int, double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’ is not derived from ‘const std::array<_Tp, _Nm>’
       ConvertString(row[Column], std::get<Column>(tuple));
                                                  ^
    In file included from tupleTest.cpp:4:0:
    /usr/include/c++/5/tuple:832:5: note: candidate: template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_Elements ...> >& std::get(std::tuple<_Elements ...>&)
         get(tuple<_Elements...>& __t) noexcept
         ^
    /usr/include/c++/5/tuple:832:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/tuple:838:5: note: candidate: template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_Elements ...> >& std::get(const std::tuple<_Elements ...>&)
         get(const tuple<_Elements...>& __t) noexcept
         ^
    /usr/include/c++/5/tuple:838:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/tuple:844:5: note: candidate: template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_Elements ...> >&& std::get(std::tuple<_Elements ...>&&)
         get(tuple<_Elements...>&& __t) noexcept
         ^
    /usr/include/c++/5/tuple:844:5: note:   substitution of deduced template arguments resulted in errors seen above
    /usr/include/c++/5/tuple:867:5: note: candidate: template<class _Tp, class ... _Types> constexpr _Tp& std::get(std::tuple<_Elements ...>&)
         get(tuple<_Types...>& __t) noexcept
         ^
    /usr/include/c++/5/tuple:867:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/tuple:873:5: note: candidate: template<class _Tp, class ... _Types> constexpr _Tp&& std::get(std::tuple<_Elements ...>&&)
         get(tuple<_Types...>&& __t) noexcept
         ^
    /usr/include/c++/5/tuple:873:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/5/tuple:879:5: note: candidate: template<class _Tp, class ... _Types> constexpr const _Tp& std::get(const std::tuple<_Elements ...>&)
         get(const tuple<_Types...>& __t) noexcept
         ^
    /usr/include/c++/5/tuple:879:5: note:   template argument deduction/substitution failed:
    I've tried it on the three versions of g++that are available to me - g++ 4.6.3, 4.7.2, and 5.3.0, and the code generates errors on all versions. I don't know what I'm doing wrong. I don't have a ton of experience with tuples, but based on info I've found on cppreference.com and other websites, it looks to me like it should work.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    The errors seem to be caused by line 47, it looks like that function might have an infinite recursion problem.

    Jim

  3. #3
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Even when I change to the following, I still get basically the same errors:
    Code:
    template <size_t Column, typename... Args>
    void ParseDbRowTuple(const std::vector<std::string>& row, std::tuple<Args...>& tuple)
    {
      ConvertString(row[Column], std::get<Column>(tuple));
    
      if (Column) ParseDbRowTuple<Column - 1>(row, tuple);
    }
    
    template <typename... Args>
    void ParseDbRowTuple(const std::vector<std::string>& row, std::tuple<Args...>& tuple)
    {
      if (std::tuple_size<std::tuple<Args...> >::value > row.size()) return;
    
      const size_t Column = std::tuple_size<std::tuple<Args...> >::value - 1;
    
      if (Column) ParseDbRowTuple<Column>(row, tuple);
    }
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  4. #4
    Registered User
    Join Date
    Aug 2010
    Location
    Poland
    Posts
    733
    This won't work. You cannot stop recursive template instantiations by a simple return statement. Return statements work at runtime, not at compile time. Recursive template instantiation must be stopped either by full specialization or partial specialization. However, partial specialization of functions is not allowed, so you have to implement your function as a functor instead:
    Code:
    template <size_t Column, typename... Args>
    struct ParseDbRowTupleImpl {
        void operator()(...) { ... }
    }
    
    template <typename... Args>
    struct ParseDbRowTupleImpl<0, Args...> {
        void operator()(...) { }
    }

  5. #5
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    I made some progress by using g++ 5.3 and C++14's std::index_sequence. I haven't got it to produce the correct output yet, but I've at least got it to be error free.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    This won't work. You cannot stop recursive template instantiations by a simple return statement. Return statements work at runtime, not at compile time. Recursive template instantiation must be stopped either by full specialization or partial specialization. However, partial specialization of functions is not allowed, so you have to implement your function as a functor instead:
    O_o

    Remember, when in doubt, pinky out!

    To be clear, the important statements aren't wrong.

    You just don't have to implement terminating behavior with a new set of template classes.

    The approach you suggest wraps a specialization around the desired terminating condition.

    You are essentially saying, with code, use a specific implementation only under specific circumstances.

    We have facilities in the standard library, beginning with C++11 standard, which say the same sort of thing in a general way.

    Soma

    Code:
    #include <string>
    #include <vector>
    #include <tuple>
    
    void ConvertString(const std::string& str, std::string& target)
    {
      target = str;
    }
    
    void ConvertString(const std::string& str, double& target)
    {
      target = std::stod(str);
    }
    
    void ConvertString(const std::string& str, float& target)
    {
      target = std::stof(str);
    }
    
    void ConvertString(const std::string& str, int& target)
    {
      target = std::stoi(str);
    }
    
    void ConvertString(const std::string& str, unsigned int& target)
    {
      target = std::stoul(str);
    }
    
    void ConvertString(const std::string& str, long& target)
    {
      target = std::stol(str);
    }
    
    void ConvertString(const std::string& str, unsigned long& target)
    {
      target = std::stoul(str);
    }
    
    template <size_t Column, typename... Args>
    std::enable_if_t<Column == std::tuple_size<std::tuple<Args...> >::value> ParseDbRowTuple(const std::vector<std::string>& row, std::tuple<Args...>& tuple)
    {
    }
    
    template <size_t Column, typename... Args>
    std::enable_if_t<Column < std::tuple_size<std::tuple<Args...> >::value> ParseDbRowTuple(const std::vector<std::string>& row, std::tuple<Args...>& tuple)
    {
      ConvertString(row[Column], std::get<Column>(tuple));
    
      ParseDbRowTuple<Column + 1>(row, tuple);
    }
    
    template <typename... Args>
    void ParseDbRowTuple(const std::vector<std::string>& row, std::tuple<Args...>& tuple)
    {
      ConvertString(row[0], std::get<0>(tuple));
    
      ParseDbRowTuple<1>(row, tuple);
    }
    
    #include <iostream>
    
    int main()
    {
      std::vector<std::string> strVec = {"1", "3.14", "foo"};
      std::tuple<int, double, std::string> tuple;
    
      std::cout << std::get<0>(tuple) << '\n';
      std::cout << std::get<1>(tuple) << '\n';
      std::cout << std::get<2>(tuple) << '\n';
      ParseDbRowTuple(strVec, tuple);
      std::cout << std::get<0>(tuple) << '\n';
      std::cout << std::get<1>(tuple) << '\n';
      std::cout << std::get<2>(tuple) << '\n';
    
      return 0;
    }
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  7. #7
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by Elkvis View Post
    Code:
    void ConvertString(const std::string& str, double& target)
    void ConvertString(const std::string& str, float& target)
    void ConvertString(const std::string& str, int& target)
    void ConvertString(const std::string& str, unsigned int& target)
    void ConvertString(const std::string& str, long& target)
    void ConvertString(const std::string& str, unsigned long& target)
    This is going to bite you one day, when you're wondering why "(string, long)" is being called instead of "(string, int)".

  8. #8
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Quote Originally Posted by phantomotap View Post
    We have facilities in the standard library, beginning with C++11 standard, which say the same sort of thing in a general way.
    I really like your solution. I haven't worked with enable_if much yet, and in fact, my primary development environment (Ubuntu 12.04/g++ 4.6.3) supports enable_if, but not enable_if_t, and also does not support the usage of the "using" keyword that would allow me to define it myself. I guess I'll have to start pressuring management to update the build environment.

    Edit: I guess I don't really need enable_if_t. It's just a convenience. Not a big deal.
    Last edited by Elkvis; 03-28-2016 at 06:51 AM.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It may not be a big deal, but using such an outdated build environment sounds like a pretty big deal to me, so I think you should do yourself a favour and try to update regardless.
    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.

  10. #10
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Quote Originally Posted by Elysia View Post
    It may not be a big deal, but using such an outdated build environment sounds like a pretty big deal to me, so I think you should do yourself a favour and try to update regardless.
    It may be outdated, but it is still supported for another year or so, and that's usually what drives the update schedule for my employer. The logic used here is that there's no reason to upgrade until it's not supported anymore.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Newer features means more productive, more readable and possibly faster code. Newer versions also pump out bug fixes and new optimizations. There's nothing worse than not being able to reply on the standard library. So I'd say that there's no reason to upgrade until it's not supported any more is nonsense. I can understand if you're stuck with a thick-headed employer who does not wish to upgrade no matter what, though.
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 02-25-2016, 08:49 AM
  2. Replies: 0
    Last Post: 10-23-2011, 07:26 AM
  3. Replies: 9
    Last Post: 03-30-2009, 04:09 AM
  4. Returning Multiple Tuples?
    By HalNineThousand in forum C++ Programming
    Replies: 5
    Last Post: 03-30-2008, 08:12 PM
  5. returning values (tuples)
    By l2u in forum C++ Programming
    Replies: 10
    Last Post: 09-20-2007, 08:24 PM