嵌套括号括起来的初始化程序列表

时间:2018-08-15 08:00:11

标签: 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>

1 个答案:

答案 0 :(得分:2)

由于嵌套的初始化程序列表是non-deduced context,因此无法使用模板参数包来实现。

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

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);
    }

    // . . .

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

完整示例:

#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;
}