【问题标题】:Initializing std::tuple from initializer list从初始化列表初始化 std::tuple
【发布时间】:2010-08-05 08:43:11
【问题描述】:

我想知道元组是否可以通过初始化列表初始化(更准确地说,通过初始化列表的初始化列表)?考虑元组定义:

typedef std::tuple< std::array<short, 3>,
                    std::array<float, 2>,
                    std::array<unsigned char, 4>,
                    std::array<unsigned char, 4> > vertex;

有没有办法做到以下几点:

static vertex const nullvertex = { {{0, 0, 0}},
                                   {{0.0, 0.0}},
                                   {{0, 0, 0, 0}},
                                   {{0, 0, 0, 0}} };

我只想实现与使用 struct 而不是 tuple 相同的功能(因此只有数组由 initializer_list 初始化):

static struct vertex {
    std::array<short, 3> m_vertex_coords;
    std::array<float, 2> m_texture_coords;
    std::array<unsigned char, 4> m_color_1;
    std::array<unsigned char, 4> m_color_2;
} const nullvertex = {
    {{0, 0, 0}},
    {{0.0, 0.0}},
    {{0, 0, 0, 0}},
    {{0, 0, 0, 0}}
};

我没有理由必须使用元组,只是想知道。我在问,因为我无法通过我尝试进行此类元组初始化而生成的 g++ 模板错误。

@Motti:所以我错过了统一初始化的正确语法 -

static vertex const nullvertex = vertex{ {{0, 0, 0}},
                                         {{0.0, 0.0}},
                                         {{0, 0, 0, 0}},
                                         {{0, 0, 0, 0}} };

和

static vertex const nullvertex{ {{0, 0, 0}},
                                {{0.0, 0.0}},
                                {{0, 0, 0, 0}},
                                {{0, 0, 0, 0}} };

但似乎所有的麻烦都在于数组,它没有用于 initializer_list 的构造函数,并且用适当的构造函数包装数组似乎不是一件容易的事。

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:

    初始化列表与元组无关。

    我认为您混淆了 C++0x 中花括号的两种不同用法。

    1. initializer_list&lt;T&gt; 是同构集合(所有成员必须属于同一类型,因此与 std::tuple 无关)
    2. Uniform initialization 是使用大括号来构造各种对象的地方;具有构造函数的数组、POD 和类。这也有解决the most vexing parse)的好处

    这是一个简化版:

    std::tuple<int, char> t = { 1, '1' }; 
    // error: converting to 'std::tuple<int, char>' from initializer list would use
    // explicit constructor 'std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&) 
    // [with _U1 = int, _U2 = char, _T1 = int, _T2 = char]'
    
    std::tuple<int, char> t { 1, '1' }; // note no assignment
    // OK, but not an initializer list, uniform initialization
    

    错误消息是你试图隐式调用构造函数,但它是显式构造函数,所以你不能。

    基本上你想要做的是这样的:

    struct A { 
        explicit A(int) {}
    };
    
    A a0 = 3;
    // Error: conversion from 'int' to non-scalar type 'A' requested
    
    A a1 = {3}; 
    // Error: converting to 'const A' from initializer list would use 
    // explicit constructor 'A::A(int)'
    
    A a2(3); // OK C++98 style
    A a3{3}; // OK C++0x Uniform initialization
    

    【讨论】:

    • 为什么用大括号初始化列表构造std::tuple 是一件坏事?它适用于std::pairs,而std::tuple 是std::pair 的概括,所以我不明白这个限制的原因:S...
    • @rubenvb 可以使用统一初始化(大括号)初始化tuple,但要这样做,您必须删除等号。如果您有等号,则表示您使用接受初始化列表的一个参数构造函数构造一个临时值,然后使用临时值的复制构造函数(尽管编译器可以省略其中的一些)。
    • 这是对@rubenvb 的一些非常糟糕的评论答案......不会引入临时的。相应的构造函数是显式的,这真是太可惜了
    • @JohannesSchaub-litb,如果我弄错了,请纠正我,但是当您编写 T t = x; 时,它要求 T 具有可访问的隐式构造函数,该构造函数接受 x 并具有可访问的复制构造函数。一旦确定t 可以从临时T 构造,编译器就可以忽略临时,否则它不应该编译。
    • 我认为简化版std::tuple&lt;int, char&gt; t = { 1, '1' }; 不好,因为std::tuple&lt;int, char&gt; t = { (int)1, (char)'1' }; 仍然会产生同样的错误。正如this 解释的那样,这里生成错误消息是因为元组没有接受initializer_list 作为tuple constructor 的构造函数,
    猜你喜欢
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-09
    • 1970-01-01
    • 2012-08-02
    • 2020-05-14
    • 1970-01-01
    相关资源
    最近更新 更多