c++ - 嵌套的大括号括起来的初始化列表

标签 c++ c++11 variadic

我的代码生成了 GCC 语法错误:

src/main.cpp: In function ‘int main()’: src/main.cpp:95:4: error:
could not convert ‘{{"enum", E_PRINT}, {"string", "setup"}, {"object",
{{"double", 3.1415926535897931e+0}, {"long", 1235813l}}}}’ from
‘<brace-enclosed initializer list>’ to ‘Object’
};
#include <cmath>
#include <initializer_list>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include <stdlib.h>

struct NamedValueBase {

   NamedValueBase( const std::string & name ) :
      name( name )
   {}

   virtual ~ NamedValueBase( void ) {}

   std::string name;
};

template<class T>
struct NamedValue : public NamedValueBase {

   NamedValue( const std::string & name, const T & value ) :
      NamedValueBase( name ),
      value( value )
   {}

   T value;
};

typedef std::shared_ptr<NamedValueBase> sharedPair;

struct Object {

   Object( void ) {}

   Object( std::initializer_list<sharedPair > attributes ) :
      pairs( std::vector<sharedPair >(
         attributes.begin(), attributes.end() ))
   {}

   template<class T>
   void add( const std::string & name, const T & value ) {
      pairs.push_back(
         sharedPair(
            new NamedValue<T>( name, value )));
   }

   void add( sharedPair nvb ) {
      pairs.push_back( nvb );
   }

   std::vector<sharedPair > pairs;
};

template<class T>
sharedPair create( const std::string & name, T value ) {
   return sharedPair( new NamedValue<T>( name, value ));
}

inline sharedPair create(
   const std::string &                name,
   std::initializer_list<sharedPair > attributes )
{
   return sharedPair(
      new NamedValue<Object>( name, Object( attributes )));
}

enum e {
   E_PRINT
};

int main() {
   // First form: OK
   Object msg = {
      create( "enum"  , E_PRINT ),
      create( "string", "setup" ),
      create( "object", {
         create(  "double", M_PI ),
         create(  "long"  , 1235813L )}
      )
   };
   std::cout << msg.pairs.size() << std::endl;

   // Second form: error: could not convert ‘{{"enum"...5813l}}}}’ from
   // ‘<brace-enclosed initializer list>’ to ‘Object’
   Object msg2 = {
      { "enum"  , E_PRINT },
      { "string", "setup" },
      { "object", {
         {  "double", M_PI     },
         {  "long"  , 1235813L }}
      }
   };
   std::cout << msg2.pairs.size() << std::endl;
   return EXIT_SUCCESS;
}
// g++ -std=c++11 src/main.cpp -o object

第一种形式的编译和执行效果很好,但我希望使用参数包语法启用第二种形式,即

template<T...Args>

最佳答案

它不能用模板参数包实现,因为嵌套的初始化列表是 non-deduced context .

诀窍是使用模板化构造函数和接受自身列表的构造函数来实现中间“构建器”类来处理嵌套情况:

struct pairBuilder {
    sharedPair ptr;

    template<typename T>
    pairBuilder(const std::string & name, const T & value) : ptr(create(name, value))
    {}

    pairBuilder(const std::string & name, std::initializer_list<pairBuilder> values) :
        ptr(create(name, values))
    {}
};

然后在 Object 中接受它们的列表:

struct Object {

    Object(std::initializer_list<pairBuilder> values) {
        for (auto& t : values)
            add(t.ptr);
    }

    // . . .

这是可行的,因为在这种情况下,类型的正常推导发生在重载解析期间,本质上是“解包”每个 braced-init-list。

完整示例:

#include <cmath>
#include <initializer_list>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

struct NamedValueBase {

    NamedValueBase(const std::string & name) :
        name(name)
    {}

    virtual ~NamedValueBase(void) {}

    std::string name;
};

typedef std::shared_ptr<NamedValueBase> sharedPair;

template<class T>
sharedPair create(const std::string & name, T value);

struct pairBuilder {
    sharedPair ptr;

    template<typename T>
    pairBuilder(const std::string & name, const T & value) : ptr(create(name, value)) {
    }

    pairBuilder(const std::string & name, std::initializer_list<pairBuilder> values) : ptr(create(name, values)) {
    }
};

template<class T>
struct NamedValue : public NamedValueBase {

    NamedValue(const std::string & name, const T & value) :
        NamedValueBase(name),
        value(value)
    {}

    T value;
};

struct Object {

    Object(void) {}

    Object(std::initializer_list<sharedPair> attributes) :
        pairs(std::vector<sharedPair >(
            attributes.begin(), attributes.end()))
    {}

    Object(std::initializer_list<pairBuilder> values) {
        for (auto& t : values)
            add(t.ptr);
    }

    template<class T>
    void add(const std::string & name, const T & value) {
        pairs.push_back(
            sharedPair(
                new NamedValue<T>(name, value)));
    }

    void add(sharedPair nvb) {
        pairs.push_back(nvb);
    }

    std::vector<sharedPair> pairs;
};

template<class T>
sharedPair create(const std::string & name, T value) {
    return sharedPair(new NamedValue<T>(name, value));
}

inline sharedPair create(
    const std::string &                name,
    std::initializer_list<pairBuilder> values)
{
    return sharedPair(
        new NamedValue<Object>(name, Object(values)));
}

enum e {
    E_PRINT
};

int main() {
    Object msg2 = {
      { "enum"  , E_PRINT },
      { "string", 2.0 },
        { "object", {
          {  "double", 3.14     },
          {  "long"  , 1235813L }}
        }
    };
    std::cout << msg2.pairs.size() << std::endl;
    return EXIT_SUCCESS;
}

关于c++ - 嵌套的大括号括起来的初始化列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51854983/

相关文章:

c++ - 将可变参数模板列表中的整数值分配给静态常量 std::array 成员

c++ - 使用OpenGL读取图像字节数组

c++ - std::string 引用、std::regex 和 boost::filesystem 的基本概念

c++保存绑定(bind)对象并在asio之后使用它

c++11 - 制作自定义的随机数分布

c++ - 将可变函数作为参数传递

c++ - 从一包嵌套包中提取每个 "leaf-pack"

c++ - Gemfire 从 cqEvent 获取错误

c++ - boost std unique_ptr 的 STL 集合的序列化

c++ - 如何使用 placement new 重新初始化字段?