简体   繁体   中英

Passing an array as reference to a std::tuple

I try to forward parameters (which may hold a reference to an array) to a tuple:

#include <iostream>
#include <tuple>
#include <type_traits>

#ifndef LOG_TYPE
#define LOG_TYPE(X) std::clog << typeid(X).name() << std::endl;
#endif

#ifndef LOG
#define LOG(X) std::clog << X << std::endl;
#endif

template <typename ... Parameters>
void pass(Parameters&& ... parameters) {
    auto tuple = std::forward_as_tuple(parameters ...);

    // std::tuple<int (&) [3]>
    LOG_TYPE(tuple);

    typedef typename std::tuple_element<0, decltype(tuple)>::type array_type;

    // int [3]
    LOG_TYPE(array_type);

    // --- The following is not the desired result ---    
    // array: 0
    LOG("array: " << std::is_array<array_type>());
}


template <typename ... Parameters>
void pass_ref(Parameters&& ... parameters) {
    auto tuple = std::forward_as_tuple(parameters ...);

    // std::tuple<std::reference_wrapper<int [3]>&>
    LOG_TYPE(tuple);

    typedef typename std::remove_reference<
        typename std::tuple_element<0, decltype(tuple)>::type>::type
        element_type;
    typedef typename element_type::type array_type;

    // int [3]
    LOG_TYPE(array_type);

    // array: 1
    LOG("array: " << std::is_array<array_type>());
}


int main() {
    int array[3];

    // array: 1
    LOG("array: " << std::is_array<decltype(array)>());

    // This is what I like:
    pass(array);
    // This works:
    pass_ref(std::ref(array));
    return 0;
}

Is there a way to get around std::ref ?

(Note: The question is not about logging, but the std::is_array<array_type>() )

#define LOG_TYPE(X) std::clog << typeid(X).name() << std::endl;

typeid is the wrong tool for inspecting this.

In the first function, array_type is not an array type because it is a reference type. The first element of tuple<int(&)[3]> is int(&)[3] , not int[3] . typeid doesn't care for top-level references, so it doesn't reflect that in that program's output.

I tend to use a construct like the following when I'm debugging template meta-programming code in order to convince the compiler to print out an exact type. Sadly it can only do so as an error message.

struct{}_ = foo; // where foo is a value of the type I want in the message

This yields something like "no conversion from to anonymous structure". Sometimes I don't have a value readily available for this, so I use std::declval or a simple template <typename T> struct show{}; .

So your fix is:

typedef typename std::remove_reference<
    typename std::tuple_element<0, decltype(tuple)>::type>::type array_type;

forward_as_tuple constructs a tuple of references to the arguments (link ) and a reference to an array is not an array. You can check by using std::is_reference<T> .

This seems to work:

template <typename ... Parameters>
void pass(Parameters& ... parameters) {
                   ^^^ no &&

    typedef std::tuple<Parameters...> tuple_type;
    LOG_TYPE(tuple);

    typedef typename std::tuple_element<0, tuple_type>::type array_type;

    // int [3]
    LOG_TYPE(array_type);

    // array: 0
    LOG("array: " << std::is_array<array_type>());
}

You can also modify your original code to drop the reference:

template <typename ... Parameters>
void pass(Parameters&& ... parameters) {
    auto tuple = std::forward_as_tuple(parameters ...);

    // std::tuple<int (&) [3]>
    LOG_TYPE(tuple);

    typedef typename std::tuple_element<0, decltype(tuple)>::type array_type_r;

    // >>> drop the reference added by forward_as_tuple
    typedef typename std::remove_reference<array_type_r>::type array_type;

    // int [3]
    LOG_TYPE(array_type);

    // array: 0
    LOG("array: " << std::is_array<array_type>());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM