1
char arr[3];
std::tuple<int,int> t1(0,0);          // perfectly OK
std::tuple<char[3],int> t2(arr,0);    // error: no matching function for call to 'std::tuple<char [3], int>::tuple(char [3], int)'

Why it cannot construct this instance? I expected that the argument array will be copied into destination. I can also construct the instance using default constructor and then assign both fields, but isn't achievable from constructor?

ardabro
  • 1,907
  • 16
  • 31
  • 8
    C style arrays are second class citizens of C++. They do things other types don't, and they can't do things most other types can. They are fine for certain limited applications, but usually it is easier to use a `std::array` instead. Consider a `std::tuple, int>` instead. – François Andrieux Mar 01 '22 at 16:05
  • 2
    The problem is [array to pointer decay](https://stackoverflow.com/q/1461432/212858) (which happens when `arr` is passed by value, except to a function which explicitly captures an array reference). The solution is indeed to use `std::array` instead - that's precisely why it exists. – Useless Mar 01 '22 at 16:18
  • [Same/simplified issue](http://coliru.stacked-crooked.com/a/0fc0e7c2ec6fb861). – PaulMcKenzie Mar 01 '22 at 16:24

2 Answers2

0

I miss the last part of the answer where I did not manage to arrange correctly 2 parameter pack expansions but I may hope to get it correctly in the future (thus I also did not take into account the efficiency and the potential number of copies performed)

Also I do not know if in your example you wanted

  • a tuple of 2 members ( the first one being the array )
  • a N+p dimensional tuple ( where N is the dimension of the array and p the dimension of other potential tuple members ).

I choose to try the second one as it is the most difficult answer. Otherwise you can convert your plain old array T arr[N] to std::array<T,N> as it is described in cpp reference std::integer_sequence which was a source of inspiration ( Indices{} )

Another source of inspiration is Bartolomiej Filipek blog article on tuple iteration

#include <iostream>
#include <tuple>

template <typename U, size_t N, size_t... Is, typename Others> auto makeTupleN_impl(const U (&arr)[N], std::index_sequence<Is...>, Others others) { 
    return std::tuple_cat(std::tie(arr[Is]... ), others);
}

template <typename U, size_t N, typename Indices = std::make_index_sequence<N>, typename... Others> auto makeMyTuple(const U (&arr)[N], Others... others) { 
    return makeTupleN_impl(arr,Indices{},std::make_tuple(others...));
}

int main()
{
    char  arr[] = {31, 32, 33, 34, 35, 36, 37, 38};

    auto c = makeMyTuple(arr,-11,-222);
    
    std::cout << (int)std::get<7>(c) << " " << (int)std::get<8>(c) <<  " " << (int)std::get<9>(c) <<"\n";

    return 0;
}

Printout is : 38 -11 -222

NGI
  • 852
  • 1
  • 12
  • 31
0

I thought to another answer simpler than my first one, use std::reference_wrapper as you can't have tuple of references but you can have tuple of reference_wrappers.

However this does still not answer your question as there is no copy and the lifetime of your source array must be guaranteed elsewhere...

#include <iostream>
#include <tuple>
#include <functional>

int main()
{
    char  arr[] = {31, 32, 33, 34, 35, 36, 37, 38};
    
    auto t = std::make_tuple(std::ref(arr),11);
    
    std::cout << (int)std::get<0>(t)[7] << " " << std::get<1>(t) <<"\n" << std::flush;

    return 0;
}

output is 38 11

I expect no limitations compared to usual syntax

NGI
  • 852
  • 1
  • 12
  • 31