我尝试将参数(可能包含对数组的引用)转发给元组:
#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;
}
有没有办法绕过std::ref
?
(注意:问题不是关于记录,而是std::is_array<array_type>()
)
答案 0 :(得分:1)
#define LOG_TYPE(X) std::clog << typeid(X).name() << std::endl;
typeid
是检查此错误的错误工具。
在第一个函数中,array_type
不是数组类型,因为它是引用类型。 tuple<int(&)[3]>
的第一个元素是int(&)[3]
,而不是int[3]
。 typeid
并不关心顶级参考,因此它并未反映该计划的输出。
当我调试模板元编程代码时,我倾向于使用类似下面的结构,以说服编译器打印出确切的类型。可悲的是,它只能作为错误信息。
struct{}_ = foo; // where foo is a value of the type I want in the message
这会产生类似&#34;没有从匿名结构转换到#34;。有时我没有随时可用的值,因此我使用std::declval
或简单的template <typename T> struct show{};
。
所以你的修复是:
typedef typename std::remove_reference<
typename std::tuple_element<0, decltype(tuple)>::type>::type array_type;
答案 1 :(得分:1)
forward_as_tuple
构造对参数(link)的引用元组,对数组的引用不是数组。您可以使用std::is_reference<T>
进行检查。
这似乎有效:
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>());
}
您还可以修改原始代码以删除参考:
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>());
}