C ++ Direct call of member function without template for template function

I would like to hide std :: tuple in my Record class and provide it with a [] operator to access the tuple elements. The naive code that does not compile is this:

#include <tuple>

template <typename... Fields>
class Record {
  private:
    std::tuple<Fields...> list;

  public:
    Record() {}

    auto operator[](std::size_t n)
            -> decltype(std::get<1u>(list)) {
        return std::get<n>(list);
    }
};

int main() {
    Record<int, double> r;
    r[0];
    return 0;
}

g ++ 4.6 says:

x.cc:13:32: error: no matching function for call toget(std::tuple<int, double>&)’
x.cc:13:32: note: candidates are:
/usr/include/c++/4.6/utility:133:5: note: template<unsigned int _Int, class _Tp1, class _Tp2> typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/utility:138:5: note: template<unsigned int _Int, class _Tp1, class _Tp2> const typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(const std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/tuple:531:5: note: template<unsigned int __i, class ... _Elements> typename std::__add_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(std::tuple<_Elements ...>&)
/usr/include/c++/4.6/tuple:538:5: note: template<unsigned int __i, class ... _Elements> typename std::__add_c_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(const std::tuple<_Elements ...>&)

Basically, I would like to name the Record::operator[]same as on an array. is it possible?

+5
source share
6 answers

An argument getis a compile-time constant. You cannot use runtime for this, and you cannot have a single function that returns members tuple, since your return type will be incorrect. What you can do is abuse the non-type arguments:

#include <tuple>

template<typename... Args>
struct Foo {
  std::tuple<Args...> t;

  template<typename T, std::size_t i>
  auto operator[](T (&)[i]) -> decltype(std::get<i>(t)) {
    return std::get<i>(t);
  }
  // also a const version
};

int main()
{
  Foo<int, double> f;
  int b[1];
  f[b];
  return 0;
}

, , . get .

, , . ( - virtual). , non-type ( constexpr) -, , , . .

+3

, , , :

 auto operator[](std::size_t n)
            -> decltype(std::get<1u>(list)) {
        return std::get<n>(list);
    }

n to std::get , n not .

+2

, Xeo , .

, . , [] .

template<typename T, std::size_t N = std::tuple_size<T>::value - 1>
struct foo {
  static inline auto bar(std::size_t n, const T& list)
          -> decltype(((n != N) ? foo<T, N-1>::bar(n, list) : std::get<N>(list))) {
      return ((n != N) ? foo<T, N-1>::bar(n, list) : std::get<N>(list));
  }
};

template<typename T>
struct foo<T, 0> {
  static inline auto bar(std::size_t n, const T& list)
          -> decltype(std::get<0>(list)) {
      return std::get<0>(list);
  }
};

template <typename... Fields>
class Record {
  private:
    std::tuple<Fields...> list;

  public:
    Record() {
      std::get<0>(list) = 5;
    }

    inline auto operator[](std::size_t n) 
            -> decltype(foo<decltype(list)>::bar(n, list)) {
            return foo<decltype(list)>::bar(n, list);
    }
};

int main() {
    Record<int, double> r;
    std::cout << r[0];
    return 0;
}
+2

.

, (, ), , .

, :

Record<Apple, Orange> fruitBasket;

:

  • decltype(fruitBasket[0]) Apple
  • decltype(fruitBasket[1]) Orange

?

++ ( ). ( ) .

, , , .

:

  • , ( )
  • ,

( ), , , .

, , . ? , (?) , .

+2

Since it nis a template parameter, it must be known at compile time, but you want to pass it as a parameter at run time.

In addition, gcc 4.5.2 is not satisfied with this fact:

g++ 1.cpp -std=c++0x
1.cpp: In member function 'decltype (get<1u>(((Record<Fields>*)0)->Record<Fields>::list)) Record<Fields>::operator[](size_t)':
1.cpp:14:25: error: 'n' cannot appear in a constant-expression
0
source

If you're fine with a compile-time constant and still want to have good syntax operator[], this is an interesting workaround:

#include <tuple>

template<unsigned I>
struct static_index{
  static unsigned const value = I;
};

template <typename... Fields>
class Record {
  private:
    typedef std::tuple<Fields...> tuple_t;
    tuple_t list;

  public:
    Record() {}

    template<unsigned I>
    auto operator[](static_index<I>)
        -> typename std::tuple_element<
               I, tuple_t>::type&
    {
        return std::get<I>(list);
    }
};

namespace idx{
const static_index<0> _0 = {};
const static_index<1> _1 = {};
const static_index<2> _2 = {};
const static_index<3> _3 = {};
const static_index<4> _4 = {};
}

int main() {
    Record<int, double> r;
    r[idx::_0];
    return 0;
}

Live example on Ideone. Although I personally just advise doing this:

// member template
template<unsigned I>
auto get()
    -> typename std::tuple_element<
           I, tuple_t>::type&
{
    return std::get<I>(list);
}

// free function
template<unsigned I, class... Fields>
auto get(Record<Fields...>& r)
  -> decltype(r.template get<I>())
{
  return r.template get<I>();
}

Live example on Ideone.

0
source

All Articles