2

我正在尝试从类构造函数的构造函数的初始化列表中的initialization_list 使一个类可初始化。它适用于 std::map,但不适用于我的自定义类。除了在 std::map 中使用模板之外,我没有看到任何区别。

#include <iostream>
#include <initializer_list>

#include <string>
#include <sstream>
#include <map>
using std::string;

class text_thing
{
private:
    string m_text;

public:
    text_thing()
    {

    }

    text_thing(text_thing& other);
    text_thing(std::initializer_list< std::pair<const string, const string> >& il);

    text_thing& operator=(std::initializer_list< std::pair<const string, const string> >& il);

    operator string()
    {
        return m_text;
    }

};


class static_base
{
private:
    std::map<string, string> m_test_map;
    text_thing m_thing;

    static_base();


public:
    static static_base& getInstance()
    {
        static static_base instance;
        return instance;
    }

    string getText()
    {
        return (string)m_thing;
    }

};


typedef std::pair<const string, const string> spair;

text_thing::text_thing(text_thing& other)
{
    m_text = other.m_text;
}

text_thing::text_thing(std::initializer_list< std::pair<const string, const string> >& il)
{
    std::stringstream text_gen;
    for (auto& apair : il)
    {
        text_gen << "{" << apair.first << ", " << apair.second << "}" << std::endl;
    }
}

text_thing& text_thing::operator=(std::initializer_list< std::pair<const string, const string> >& il)
{
    std::stringstream text_gen;
    for (auto& apair : il)
    {
        text_gen << "{" << apair.first << ", " << apair.second << "}" << std::endl;
    }

    return *this;
}

static_base::static_base() :
        m_test_map{{"test", "1"}, {"test2", "2"}},  // Compiler fine with this
        m_thing{{"test", "1"}, {"test2", "2"}}      // Compiler doesn't like this
{

}

int main()
{

    std::cout << "Starting the program" << std::endl;

    std::cout << "The text thing: " << std::endl << static_base::getInstance().getText();

}

我得到这个编译器输出

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"static_base.d" -MT"static_base.d" -o "static_base.o" "../static_base.cpp"
Finished building: ../static_base.cpp

Building file: ../test.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"test.d" -MT"test.d" -o "test.o" "../test.cpp"
../test.cpp: In constructor ‘static_base::static_base()’:
../test.cpp:94:40: error: no matching function for call to ‘text_thing::text_thing(<brace-enclosed initializer list>)’
   m_thing{{"test", "1"}, {"test2", "2"}}
                                        ^
../test.cpp:94:40: note: candidates are:
../test.cpp:72:1: note: text_thing::text_thing(std::initializer_list<std::pair<const std::basic_string<char>, const std::basic_string<char> > >&)
 text_thing::text_thing(std::initializer_list< std::pair<const string, const string> >& il)
 ^
../test.cpp:72:1: note:   candidate expects 1 argument, 2 provided
../test.cpp:67:1: note: text_thing::text_thing(text_thing&)
 text_thing::text_thing(text_thing& other)
 ^
../test.cpp:67:1: note:   candidate expects 1 argument, 2 provided
../test.cpp:23:2: note: text_thing::text_thing()
  text_thing()
  ^
../test.cpp:23:2: note:   candidate expects 0 arguments, 2 provided
make: *** [test.o] Error 1

gcc -v 的输出

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.1-2ubuntu1~13.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu                                                                                                                                                                                                     
Thread model: posix                                                                                                                                                                                                                                                            
gcc version 4.8.1 (Ubuntu 4.8.1-2ubuntu1~13.04) 

它与以这种方式构造的 std::map 一起编译得很好,如果我修改 static_base 以从映射中返回字符串,一切都很好而且花花公子。

请帮助我了解这里发生了什么。

4

2 回答 2

3

std::initializer_list是按值传递的,而不是按引用传递的。将您的构造函数和赋值运算符更改text_thing为按值接受而不是引用(Live at Coliru):

class text_thing
{
    // snip other stuff

    text_thing(std::initializer_list< std::pair<const string, const string> > il);
    text_thing& operator=(std::initializer_list< std::pair<const string, const string> > il);
};

text_thing::text_thing(std::initializer_list< std::pair<const string, const string> > il)
{
    std::stringstream text_gen;
    for (auto& apair : il)
    {
        text_gen << "{" << apair.first << ", " << apair.second << "}" << std::endl;
    }
}

text_thing& text_thing::operator=(std::initializer_list< std::pair<const string, const string> > il)
{
    std::stringstream text_gen;
    for (auto& apair : il)
    {
        text_gen << "{" << apair.first << ", " << apair.second << "}" << std::endl;
    }

    return *this;
}
于 2013-11-12T21:59:17.370 回答
1

给定示例,我认为它正在尝试将其打印initializer_list到输出中。它仅在将stringstream结果分配给 private后才对我有用m_text

text_thing::text_thing(std::initializer_list< std::pair<const string, const string> > il)
{
    std::stringstream text_gen;
    for (auto& apair : il)
    {
        text_gen << "{" << apair.first << ", " << apair.second << "}" << std::endl;
    }
    m_text = text_gen.str(); // store result here
}

也使用Casey的更正,这是我的工作版本:

#include <map>
#include <string>
#include <sstream>
#include <iostream>
#include <initializer_list>

using std::string;
using str_pair = std::pair<const string, const string>;
using str_pair_il = std::initializer_list<str_pair>;

///////////////////////////////////////////////////////

class Text
{
    string m_text;
    void read(str_pair_il ini);

  public:
    operator string() { return m_text; }

    Text(str_pair_il ini) {
      read(ini);
    }

    Text& operator=(str_pair_il ini) {
      read(ini);
      return *this;
    }
};

void Text::read(str_pair_il ini)
{
  std::stringstream stream;

  for (auto& pair : ini) {
    stream << "{" << pair.first << ", " << pair.second
           << "}" << std::endl;
  }

  m_text = stream.str();
}

///////////////////////////////////////////////////////

class StaticBase
{
    std::map<std::string, std::string> m_map;
    Text m_txt;

    StaticBase(); // private constructor for singleton

  public:
    std::string getText() { return m_txt; }

    static StaticBase& getInstance() {
      static StaticBase instance;
      return instance;
    }
};

StaticBase::StaticBase()
  : m_map{{"test", "1"}, {"test2", "2"}},
    m_txt{{"test", "1"}, {"test2", "2"}}
  {}

///////////////////////////////////////////////////////

int main()
{
    std::cout << "Starting the program \n";
    std::cout << "The text thing: \n";

    std::cout << StaticBase::getInstance().getText();
}
于 2017-04-20T04:16:13.850 回答