C++ 迭代类成员

C++ 迭代类成员,c++,c++11,c++17,C++,C++11,C++17,嗨,我想知道我是否可以迭代类成员,这样就不必为每个类成员都使用writeElement 我很想让它成为for循环,这样它就可以循环所有的公共成员 我的代码: class Student { public: string name; string lastName; int age; string gender; vector<int> grades; public: void read(istream& in) {

嗨,我想知道我是否可以迭代类成员,这样就不必为每个类成员都使用
writeElement

我很想让它成为for循环,这样它就可以循环所有的公共成员

我的代码:

class Student
{
public:
    string name;
    string lastName;
    int age;
    string gender;
    vector<int> grades;

public:
    void read(istream& in)
    {
        readElement(in, name);
        readElement(in, lastName);
        readElement(in, age);
        readElement(in, gender);
        readElement(in, grades);
    }

    void write(ostream& out)
    {
        //add a loop here
        writeElement(out, name);
        writeElement(out, lastName);
        writeElement(out, age);
        writeElement(out, gender);
        writeElement(out, grades);
    }
};
班级学生
{
公众:
字符串名;
字符串lastName;
智力年龄;
字符串性别;
病媒等级;
公众:
无效读取(istream&in)
{
readElement(in,name);
readElement(in,lastName);
readElement(in,age);
readElement(中文,性别);
readElement(in,grades);
}
无效写入(ostream&out)
{
//在这里添加一个循环
writeElement(out,name);
writeElement(out,lastName);
写元素(out,age);
writeElement(外,性别);
减记要素(外,等级);
}
};

实现你的愿望没有简单的方法。为C++20提出的静态反射将使这成为可能

现在,您有几个(不太好)选择:

  • 手动写出
    readElement
    /
    writeElement
    调用。通过提供高阶函数并将
    readElement
    /
    writeElement
    作为参数传递(有点像访问者),可以避免重复

  • 将整个结构定义包装到可变宏中,该宏会自动在每个数据成员上生成访问者

  • 使用
    std::tuple
    而不是
    struct
    ,并使用
    std::apply
    +变量泛型lambda对成员进行“迭代”

  • 如果您的类型支持它,您可以使用,它(ab)使用结构化绑定和其他疯狂的元编程技巧来提供有限形式的静态反射


访客解决方案示例:

template <typename F>
void visit(F&& f)
{
    f(name);
    f(lastName);
    f(age);
    f(gender);
    f(grades);   
}

void read(istream& in)
{
    visit([&in](auto&& x){ readElement(in, x); });
}

void write(ostream& out)
{
    visit([&in](auto&& x){ writeElement(in, x); });
}
std::tuple
<
    string      /* name */,
    string      /* lastName */,
    int         /* age */,
    string      /* gender */,
    vector<int> /* grades */
> data;

template <typename F>
void visit(F&& f)
{
    std::apply([](auto&&... xs){ (f(xs), ...); }, data);
}
模板
无效访问(F&F)
{
f(姓名);
f(姓氏);
f(年龄);
f(性别);
f(职系);
}
无效读取(istream&in)
{
访问([&in](auto&&x){readElement(in,x);});
}
无效写入(ostream&out)
{
访问([&in](auto&&x){writeElement(in,x);});
}

元组解决方案示例:

template <typename F>
void visit(F&& f)
{
    f(name);
    f(lastName);
    f(age);
    f(gender);
    f(grades);   
}

void read(istream& in)
{
    visit([&in](auto&& x){ readElement(in, x); });
}

void write(ostream& out)
{
    visit([&in](auto&& x){ writeElement(in, x); });
}
std::tuple
<
    string      /* name */,
    string      /* lastName */,
    int         /* age */,
    string      /* gender */,
    vector<int> /* grades */
> data;

template <typename F>
void visit(F&& f)
{
    std::apply([](auto&&... xs){ (f(xs), ...); }, data);
}
std::tuple
<
字符串/*名称*/,,
字符串/*lastName*/,,
int/*年龄*/,,
字符串/*性别*/,,
矢量/*等级*/
>数据;
模板
无效访问(F&F)
{
std::apply([](自动&&…xs){(f(xs),…);},数据);
}

因为您正在寻找的功能还不完全存在;也许这种性质的东西会对你有所帮助。目前,我已经测试了一些基本功能,但还没有进行任何详尽的测试,所以我确实编译并运行了它。我从student类中将所有学生信息抽象为一个成员,该成员是一个元组,带有一些重载运算符()。使其按原样工作;我必须为向量和元组重载ostream和istream操作符,这样才能工作

#include <iostream>
#include <string>
#include <utility>
#include <tuple>
#include <vector>

// ostream operator<< for vector<T>
template<class T>
std::ostream& operator<<( std::ostream& out, const std::vector<T>& v ) {
    out << "{ ";
    for( auto& a : v )
        out << a << ' ';
    out << '}';
    return out;
}

// istream operator>> for vector<T>
template<class T>
std::istream& operator>>( std::istream& in, std::vector<T>& v ) {
    int i;
    std::string line;
    std::getline( std::cin, line );
    std::istringstream iss( line );
    while( iss >> i ) {
        v.push_back( i );
    }
    return in;
}

// function templates & ostream operator<< for tuple<T>
template<std::size_t> struct int_ {};

template<class Tuple, size_t Pos>
std::ostream& print_tuple( std::ostream& out, const Tuple& t, int_<Pos> ) {
    out << std::get<std::tuple_size<Tuple>::value - Pos>( t ) << ' ';
    return print_tuple( out, t, int_<Pos - 1>() );
}

template<class Tuple>
std::ostream& print_tuple( std::ostream& out, const Tuple& t, int_<1> ) {
    return out << std::get<std::tuple_size<Tuple>::value - 1>( t );
}

template<class... Args>
std::ostream& operator<<( std::ostream& out, const std::tuple<Args...>& t ) {
    return print_tuple( out, t, int_<sizeof...(Args)>() );
}

// function templates & istream operator << for tuple<T>
template<class Tuple, size_t Pos>
std::istream& write_tuple( std::istream& in, Tuple& t, int_<Pos> ) {
    in >> std::get<std::tuple_size<Tuple>::value - Pos>( t );
    return write_tuple( in, t, int_<Pos - 1>() );
}

template<class Tuple>
std::istream& write_tuple( std::istream& in, Tuple& t, int_<1> ) {
    return in >> std::get<std::tuple_size<Tuple>::value - 1>( t );
}

template<class... Args>
std::istream& operator>>( std::istream& in, std::tuple<Args...>& t ) {
    return write_tuple( in, t, int_<sizeof...(Args)>() );
}
// --------------------------------------------------

// class proto type for friend operators
template<class... T>
class StudentInfo;

template<class... T>
std::ostream& operator<< <>( std::ostream& out, const StudentInfo<T...>& c );

template<class... T>
std::istream& operator>> <>( std::istream& in, StudentInfo<T...>& c );

//template<typename... Args>
template<class...Args>
class StudentInfo {
public
    std::tuple<Args...> members;


    explicit StudentInfo(Args&&... args ) {
        members = std::make_tuple<Args...>( std::move( args )... );
    } 

    const StudentInfo<Args...>& operator() ( Args&&... args ) {
        members = std::make_tuple<Args...>( std::forward<Args>( args )... );
        return *this;
    }

    const StudentInfo<Args...> operator() ( Args&&... args ) const {
        members = std::make_tuple<Args...>( std::forward<Args>( args )... );
        return *this;
    }

    template<Args...>
    friend std::ostream& operator<< <>(std::ostream& out, const StudentInfo<Args...>& c);

    template<Args...>
    friend std::istream& operator>> <>( std::istream& in, StudentInfo<Args...>& c );

    StudentInfo<Args...>& operator=( StudentInfo<Args...>& c ) {
        if ( members == c.members ) 
            return *this;
        members = c.members;
        return *this;
    }

};

template<class... T>
std::ostream& operator<< <>( std::ostream& out, StudentInfo<T...>& c ) {
    return out << c.members;
}

template<class... T>
std::istream& operator>> <>( std::istream& in, StudentInfo<T...>& c ) {
    return in >> c.members;
}
#包括
#包括
#包括
#包括
#包括
//ostream操作员(std::istream&in、StudentInfo&c);
StudentInfo&operator=(StudentInfo&c){
if(成员==c.members)
归还*这个;
成员=c成员;
归还*这个;
}
};
模板
std::ostream&operator(std::istream&in,StudentInfo&c){
返回>>c.members;
}
使用方法如下:

int main() {
    std::string first{ "Some" };
    std::string last{ "Day" };
    int age = 1000;
    std::string sex{ "Unknown" };
    std::vector<int> grades{ 99, 98, 97, 92, 89, 88 };

    // create student info
    StudentInfo< std::string, std::string, int,
                 std::string, std::vector<int> > 
        studentA( std::move(first), std::move(last), 
                  std::move(age), std::move(sex), 
                  std::move(grades)
        );

    // outstream student info
    std::cout << studentA << '\n';

    // reset temps
    first.clear();
    last.clear();
    age = 0;
    sex.clear();
    grades.clear();

    // create 2nd student & assign new information from user input
    StudentInfo< std::string, std::string, int,
                 std::string, std::vector<int> >
        studentB( std::move(first), std::move(last), 
                  std::move(age), std::move(sex), 
                  std::move(grades)
        );

    // Check to make sure it has empty fields
    std::cout << "Student B's information\n" << studentB << '\n';

    // Now let's enter some stuff from the console and populate studentB
    std::cout << "\nEnter the student's information\n";
    std::cin >> studentB;

    // Let's check studentB's info
    std::cout << studentB << '\n';

    // Another step let's check our assignment operator
    StudentInfo< std::string, std::string, int,
                 std::string, std::vector<int> >
        studentC( std::move( first ), std::move( last ),
                  std::move( age ), std::move( sex ),
                  std::move( grades ) 
        );

    // Check studentC it should be empty
    std::cout << "Student C's information\n" << studentC << '\n';

    // Let's set studentC to studentA;
    studentC = studentA;

    // Print C's info
    std::cout << "Student C's new information\n" << studentC << '\n';

    // Finally test out the operator()
    studentC( std::move( std::get<0>( studentB.members ) ),
              std::move( std::get<1>( studentB.members ) ),
              std::move( std::get<2>( studentB.members ) ),
              std::move( std::get<3>( studentB.members ) ),
              std::move( std::get<4>( studentB.members ) )
    );
    std::cout << studentC << '\n';


    std:cout << "\nPress any key and enter to quit.\n";
    std::cin.get();
    return 0;
}
intmain(){
std::string第一个{“Some”};
std::string last{“Day”};
年龄=1000岁;
字符串性别{“未知”};
病媒等级{99,98,97,92,89,88};
//创建学生信息
StudentInfo
学生(标准::移动(第一个),标准::移动(最后一个),
标准::移动(年龄),标准::移动(性别),
标准::移动(等级)
);
//扩展学生信息

std::cout没有简单的内置方法。如果我们得到反射,可能会出现C++20。看看boost序列化。没有确定类型成员的标准机制。也许你可以使用自己填充的成员指针的
std::tuple
。你可以检查这家伙的解决方案——但它有它的局限性。如果你将学生视为共享的\u ptr,您可以在学生内部维护一个弱的\u ptr向量以供编写。元组解决方案(或
自动作为\u tuple()
成员)的一个好处是,您可以免费获得比较