Как я могу использовать концепцию повышения посетителя с классом, содержащим переменные состояния?

Я пытаюсь использовать boost :: static_visitor для реализации действий над типом boost :: variable, которые влияют на состояние некоторой переменной. Мой подход состоял в том, чтобы содержать все переменные состояния в моем классе посетителя команды, но кажется, что это невозможно.

Вот мой пример кода:

#include <string>
#include <sstream>
#include <vector>
#include <boost/variant.hpp>
#include <boost/foreach.hpp>struct TypeA
{
int varA;
int varB;
};

struct TypeB
{
std::string varA;
std::string varB;
};

typedef boost::variant<TypeA, TypeB> MyVariantType;

class MyCommandVisitor : public boost::static_visitor<>
{
public:
//These are just examples, the actions only need to be able to touch
// internal variables.
void operator()(TypeA & t) const
{
m_runningSum += t.varA;
m_outStream << "TYPEA ACTION: " << t.varB << std::endl;
}

void operator(TypeB & t) const
{
m_charCount += t.varA.size();
m_outStream << t.varB <<  " ACTION " << t.varA << std::endl;
}

std::string emitWork(std::vector<MyVariantType> listOfVariants)
{
m_outStream.clear();
m_runningSum = 0;
m_charCount = 0;
BOOST_FOREACH(MyVariantType & v, listOfVariants)
{
boost::apply_visitor(*this, v);
}
return m_outStream.str();
}

protected:
int m_runningSum;
int m_charCount;
std::stringstream outStream;
}; //End class MyCommandVisitorint main(int argc, char **argv)
{
TypeA ta;
ta.varA = 1;
ta.varB = 2;

TypeB tb;
tb.varA = "String1";
tb.varB = "String2";
std::vector<MyVariantType> listOfWork;
listOfWork.push_back(ta);
listOfWork.push_back(tb);
MyCommandVisitor myCV;

std::string result = myCV.emitWork(listOfWork);

std::cout << "Result:\n" << result << std::endl << std::endl;
return 0;
}

Надеюсь, этот фрагмент поможет понять, что я пытаюсь сделать. Однако он не скомпилируется, выдав [перефразированную] ошибку:

error: no operator "<<" matches these operands
operand types are: const std::stringstream << const char [N]
m_outStream << "TYPE A ACTION: " << t.varB << std::endl;
^

Я предполагаю, что эта ошибка связана с модификатором const, который должен быть помещен в конец прототипа функции operator (), что заставляет компилятор полагать, что переменные-члены не могут быть изменены функцией.

Мой вопрос таков:

Как правильно выполнить шаблон посетителя (используя boost :: option) с переменными, которые должны поддерживать состояние между посещениями?

1

Решение

Было несколько опечаток, но я сделал несколько модов, и теперь это работает. По сути, ваш класс static_visitor меняет себя при каждом посещении, поэтому методы operator () не могут быть константными.

#include <string>
#include <sstream>
#include <vector>
#include <boost/variant.hpp>
#include <boost/foreach.hpp>
#include <iostream>struct TypeA
{
int varA;
int varB;
};

struct TypeB
{
std::string varA;
std::string varB;
};

typedef boost::variant<TypeA, TypeB> MyVariantType;

class MyCommandVisitor : public boost::static_visitor<>
{
public:
//These are just examples, the actions only need to be able to touch
// internal variables.
void operator()(TypeA & t)
{
m_runningSum += t.varA;
m_outStream << "TYPEA ACTION: " << t.varB << std::endl;
}

void operator()(TypeB & t)
{
m_charCount += t.varA.size();
m_outStream << t.varB <<  " ACTION " << t.varA << std::endl;
}

std::string emitWork(std::vector<MyVariantType> listOfVariants)
{
m_outStream.clear();
m_runningSum = 0;
m_charCount = 0;
BOOST_FOREACH(MyVariantType & v, listOfVariants)
{
boost::apply_visitor(*this, v);
}
return m_outStream.str();
}

protected:
int m_runningSum;
int m_charCount;
std::stringstream m_outStream;
}; //End class MyCommandVisitorint main(int argc, char **argv)
{
TypeA ta;
ta.varA = 1;
ta.varB = 2;

TypeB tb;
tb.varA = "String1";
tb.varB = "String2";
std::vector<MyVariantType> listOfWork;
listOfWork.push_back(ta);
listOfWork.push_back(tb);
MyCommandVisitor myCV;

std::string result = myCV.emitWork(listOfWork);

std::cout << "Result:\n" << result << std::endl << std::endl;
return 0;
}

работает на http://www.compileonline.com/compile_cpp11_online.php дает:

Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1

Executing the program....
$demo
Result:
TYPEA ACTION: 2
String2 ACTION String1
6

Другие решения

Я лично предпочел бы сделать функтор const. Вместо этого мне нравится связывать аргументы функтора со ссылками:

static std::string emitWork(std::vector<MyVariantType> const listOfVariants) {
int sum = 0, charCount = 0;
std::stringstream os;
BOOST_FOREACH(MyVariantType const& v, listOfVariants) {
boost::apply_visitor(
boost::bind(MyCommandVisitor(), _1, boost::ref(os), boost::ref(sum), boost::ref(charCount)),
v);
}
return os.str();
}

Обратите внимание, что

  • emitWork теперь может быть статическим, входящим и т. д.
  • operator() теперь может быть const

Остальная часть посетителя будет выглядеть так:

struct MyCommandVisitor : boost::static_visitor<> {
void operator()(TypeA const& t, std::stringstream& os, int& sum, int& /*charCount*/) const {
sum += t.varA;
os << "TYPEA ACTION: " << t.varB << std::endl;
}

void operator()(TypeB const& t, std::stringstream& os, int& /*sum*/, int& charCount) const {
charCount += t.varA.size();
os << t.varB << " ACTION " << t.varA << std::endl;
}
};

Видеть это Жить на Колиру

3

По вопросам рекламы [email protected]