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.