【问题标题】:Access tuple element in C++11 via compile time variable in function通过函数中的编译时变量访问 C++11 中的元组元素
【发布时间】:2013-05-07 17:21:43
【问题描述】:

以下最小示例使用 g++ -std=c++11 -Wall tuple.cpp -o tuple 编译:

#include <tuple>
#include <iostream>

template<int i>
char get_elem_i(std::tuple<char, char> t)
{
    return std::get<i>(t);
}

int main()
{
    std::tuple<char, char> t('H','i');
    char c = get_elem_i<0>(t);
    std::cout << "The char is: " << c << std::endl;
}

现在,我不想使用指定索引的模板(确切原因:我有自动推导的模板,我不想全部指定)。所以我的第一次尝试是:

char get_elem_i(int i, std::tuple<char, char> t)
{
    return std::get<i>(t);
}

我知道这不能编译。有什么方法可以确保编译器在编译时知道i?也许是这样的?

char get_elem_i(compile_time_known int i, std::tuple<char, char> t)

【问题讨论】:

    标签: c++ c++11 stdtuple


    【解决方案1】:

    您可以使用std::array 代替std::tuple。在给出的示例中,元组的成员都具有相同的类型。

    所以,我们可以这样做:

    char get_elem_i(int i, std::array<char, 2> t)
    {
        return t[i];
    }
    

    以下是您给出的示例的一个轻微变体,以说明为什么在一般情况下不能直接实现:

    ???? get_elem_i(int i, std::tuple<char, struct foo, class bar> t) {
        return std::get<i>(t);
    }
    

    该函数的返回类型是什么? char? struct foo?


    你总是可以这样写一个函数:

    char get_elem_i(int i, std::tuple<char, char> t) {
        switch (i) {
            case 0: return std::get<0>(t);
            case 1: return std::get<1>(t);
        }
    
        assert(false);
    }
    

    【讨论】:

    • "那个函数的返回类型是什么?"我想说这实际上不是问题 - 您可以使用 auto ... -&gt; decltype(...) 类型的函数声明来解决该问题。问题是int i 参数被用作std::get&lt;i&gt; 中的模板参数。
    • @TimothyShields:当然,decltype 的结果是什么?变种? i 是模板参数的原因是因为 std::get 的返回类型根据该输入而变化。
    • @TimothyShields:我也同意我的中间函数无法编译。就是说明i一般情况下需要是模板参数。
    • @sharth 谢谢,开关工作!这是唯一/最好的解决方案吗?我只是问,因为它仍然是 4 行代码,而且可能不是运行时完美的。如果在接下来的几天内没有解决方案,我会接受你的回答。
    • @sharth 还有一个问题:开关依赖于知道 std::tuple 的类型。所以我不能对元组类型使用模板。
    【解决方案2】:

    如果您可以在编译时知道i 的值,那么您可以通过将i 的逻辑包装在constexpr 中来绕过指定i 的显式值。

    例如:

    #include <tuple>
    #include <iostream>
    
    constexpr int compile_time_known_i(int input) { return input / 3; }
    
    template<int i>
    char get_elem_i(std::tuple<char, char> t)
    {
        return std::get<i>(t);
    }
    
    int main()
    {
        std::tuple<char, char> t('H','i');
        char c = get_elem_i<0>(t);
        char d = get_elem_i<compile_time_known_i(3)>(t);
        std::cout << "The char is: " << c << " " << d <<  std::endl;
    }
    

    鉴于您的 i 可以在编译时知道,这可能有助于清理事情(尽管这有多大意义取决于您的用例)。

    如果它是传递参数的语法,您可以使用预处理器来实现这一点 - 使用一些可选的type_traits 安全性。

    #include <tuple>
    #include <iostream>
    #include <type_traits>
    
    #define get_elem_i_ct(i, t)                                                                \
        std::get<i>(t);                                                                        \
        static_assert(std::is_integral<decltype(i)>::value, #i " must be an integral type");   \
        static_assert(std::is_same<decltype(t), std::tuple<char, char>>::value, #t " must be a tuple");
    
    int main()
    {
        std::tuple<char, char> t('H','i');
        char c = get_elem_i_ct(0, t)
        char d = get_elem_i_ct(1, t)
        std::cout << "The char is: " << c << " " << d <<  std::endl;
    }
    

    虽然这达到了规定的句法要求,但我不建议在愤怒时使用这种方法 - 几乎可以肯定有更好的解决方案来解决您的实际问题。

    【讨论】:

    • 谢谢,但这仍然需要一个模板参数。就不能用none吗?
    • 我不想使用宏。但这很有趣,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2012-11-26
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多