嵌套括号括起来的初始化程序列表 [英] nested brace-enclosed initializer lists

查看:99
本文介绍了嵌套括号括起来的初始化程序列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My code generates a syntax error with 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

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

Compilation and execution of the first form works well but I wish to enable the second form using parameter pack syntax i.e.

template<T...Args>

推荐答案

由于嵌套的初始化程序列表是

It can't be implemented with a template parameter pack because a nested initializer list is a non-deduced context.

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

The trick is to implement an intermediate "builder" class using a templated constructor and a constructor accepting a list of itself to handle the nested case:

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 中接受它们的列表:

And then accept a list of them inside Object:

struct Object {

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

    // . . .

之所以行之有效,是因为在这种情况下,从类型进行的正常推导发生在重载解析期间,本质上是解开"每个支撑初始列表.

This works because in this case the normal deduction from a type happens during overload resolution, essentially "unwrapping" each 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;
}

这篇关于嵌套括号括起来的初始化程序列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆