传递数组作为std :: tuple的引用

时间:2014-04-15 10:16:53

标签: c++ c++11

我尝试将参数(可能包含对数组的引用)转发给元组:

#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>()

2 个答案:

答案 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>());
}