不完整的类型和initializer_list

时间:2016-01-07 16:11:37

标签: c++ c++14

我正在尝试为一些元数据建模,以便序列化/反序列化C ++对象。这是抓住坚果的东西。我需要的螺栓;它使用GCC 5.2(g++ sample.cpp -std=c++14)和Clang 3.6(clang++ sample.cpp -std=c++14)进行编译。

我的问题是关于示例中的struct TypeInfo。它包含std::initializer_list本身。这符合标准吗?

#include <cstdint>
#include <initializer_list>

enum class TypeCode : std::uint8_t { BOOLEAN, INT, OBJECT, STRING, SENTINEL };

struct TypeInfo
{
    TypeCode typeCode_;

    char fieldName_[64];

    union
    {
        std::uint16_t textMinLength_;
        std::uint16_t objectVersionMajor_;
    };

    union
    {
        std::uint16_t textMaxLength_;
        std::uint16_t objectVersionMinor_;
    };

    //  set only if typeCode_ = OBJECT
    std::initializer_list < TypeInfo > objectTypeInfos_;
};

int main()
{
    TypeInfo const sti { TypeCode::STRING, "updatedBy", { .textMinLength_ = 0 }, { .textMaxLength_ = 16 } };

    TypeInfo const iti { TypeCode::INT, "amount", { 0 }, { 0 } };

    TypeInfo const oti { TypeCode::OBJECT, "startTime", { .objectVersionMajor_ = 1 }, { .objectVersionMinor_ = 0 }, {
      TypeInfo { TypeCode::INT, "weekdays", { 0 }, { 0 } },
      TypeInfo { TypeCode::INT, "timeOfDay", { 0 }, { 0 } },
      TypeInfo { TypeCode::STRING, "timezone", { .textMinLength_ = 0 }, { .textMaxLength_ = 5 } }
    } };

    TypeInfo const noti { TypeCode::OBJECT, "schedule", { .objectVersionMajor_ = 1 }, { .objectVersionMinor_ = 0 }, {
      TypeInfo { TypeCode::INT, "id", { 0 }, { 0 } },
      TypeInfo { TypeCode::STRING, "description", { .textMinLength_ = 0 }, { .textMaxLength_ = 16 } },
      TypeInfo { TypeCode::OBJECT, "startTime", { .objectVersionMajor_ = 1 }, { .objectVersionMinor_ = 0 }, {
        TypeInfo { TypeCode::INT, "weekdays", { 0 }, { 0 } },
        TypeInfo { TypeCode::INT, "timeOfDay", { 0 }, { 0 } },
        TypeInfo { TypeCode::STRING, "timezone", { .textMinLength_ = 0 }, { .textMaxLength_ = 5 } }
      } }
    } };
}

2 个答案:

答案 0 :(得分:3)

这实际上会引起当前措辞的未定义行为。在std::initializer_list<TypeInfo>实例化时,TypeInfo不完整,因此[res.on.functions] /(2.5)适用:

  

特别是,在下列情况下效果不明确:
(2.5)    - 如果使用不完整类型(3.9)作为模板参数   实例化模板组件,除非特别允许   那个组成部分。

... initializer_list还没有特别允许不完整的类型 - 但是,这显然是有缺陷的。 LWG issue 2493选择解决此问题:

  

std::initializer_list<T>的典型用例是a   T构造函数的pass-by-value参数。但是,这违反了   [res.on.functions] /2.5因为initializer_list没有特别说明   允许不完整的类型(例如std::unique_ptr   ([unique.ptr] / 5)和std::enable_shared_from_this   ([util.smartptr.enab] / 2))。

     

解决方案是复制粘贴此类相关文本   段落。

即。你的代码没问题(并且在解决上述DR之后将正式罚款)。

答案 1 :(得分:2)

§[res.on.functions] / 2:

  

特别是,在以下情况下效果不明确:
  [...]
  (2.5) - 如果在实例化模板组件时将不完整类型(3.9)用作模板参数,除非特别允许该组件。

我看不到initializer_list在不完整类型上实例化的具体限制(在[dcl.init.list]或§[support.init.list]中,至少从N4296开始)。