Правильна ли эта реализация посетителя?
Я реализую посетителя, чтобы использовать его с библиотекой вариантов буста. Я хочу знать, правильно ли специализироваться boost::static_visitor<>
с константным ссылочным типом.
Обратите внимание, что мой вопрос здесь следующий:
Есть какие-то проблемы со специализацией boost::static_visitor<>
в boost::static_visitor<const T&>
?
template<typename T>
struct my_visitor : public boost::static_visitor<const T&> {
template<typename U> const T& operator()(U& u) const {
// some code here .....
return X<U>::get_some_t(); // finally return some T.
}
};
2 ответа
Нет проблем, если вы не вернете ссылку на локальную / временную ссылку.
Кроме того, обязательно проверяйте действительность ссылки во времени (она заканчивается, когда уничтожается вариантный объект, то есть когда уничтожается сам вариант, или (!), Когда он повторно инициализируется).
Предпосылки и объяснение
Вариант содержит объект "текущего" типа элемента, и вы можете ссылаться на этот объект совершенно нормально. До тех пор, пока вариант не будет повторно инициализирован для другого типа элемента (в этом случае ссылка "просто" свисает, точно так же, как если бы закончилось время жизни объекта, на который указывает ссылка).
Так что если get_somet_t()
возвращает T&
или же T const&
(или что-то с подходящим неявным преобразованием) проблем нет.
В более простой настройке позвольте мне продемонстрировать допустимые параметры:
variant<int, std::string> v1 = 42;
int& i1 = get<int>(v1); // returns by ref, valid
i1 *= 2;
// now v1 contains the updated integer value 84
Кроме того, вы можете даже сделать варианты / просто ссылки /:
std::string s = "hello";
int answer = 42;
variant<int&, std::string&> v2(s);
get<std::string&>(v2) += " world"; // now s contains "hello world"
variant<int&, std::string&> v3(answer);
get<int&>(v3) *= 2; // now `answer` contains 84
Посмотреть все Live On Coliru
демонстрация
Иными словами, это нормально:
struct A { std::string a_property; };
struct B { std::string b_field; };
struct select_member : static_visitor<std::string&> {
std::string& operator()(A& a) const { return a.a_property; }
std::string& operator()(B& b) const { return b.b_field; }
};
int main()
{
variant<A,B> v = A { "some string" };
apply_visitor(select_member(), v) += " suffix";
std::cout << get<A>(v).a_property << "\n"; // prints "some string suffix"
}
Посмотрите это в прямом эфире на Coliru.
Что насчет этого, это аккуратно?
public interface Worker {
<T> T accept( Visitor<T> visitor);
}
public class Developer implements Worker {
@Override
public <T> T accept( Visitor<T> visitor ) {
return visitor.workAsDeveloper( this );
}
}
public class Manager implements Worker {
@Override
public <T> T accept( Visitor<T> visitor ) {
return visitor.manageAsManager( this );
}
}
public class Boss implements Worker {
@Override
public <T> T accept( Visitor<T> visitor ) {
return visitor.planLikeBoss( this );
}
}
public interface Visitor<T> {
T workAsDeveloper( Developer type );
T manageAsManager( Manager type );
T planLikeBoss( Boss type );
}
public class VisitorImpl implements Visitor<String> {
@Override
public String workAsDeveloper( Developer type ) {
return "Working hard as a Developer";
}
@Override
public String manageAsManager( Manager type ) {
return "Managing smoothly as a Manager";
}
@Override
public String planLikeBoss( Boss type ) {
return "Planning like a Boss";
}
}
public class App {
Visitor<String> visitor;
public App( Visitor<String> visitor ) {
this.visitor = visitor;
}
public static void main( String[] args ) {
// Given
App app = new App( new VisitorImpl() );
Developer developer = new Developer();
Manager manager = new Manager();
Boss boss = new Boss();
// When
app.run( developer );
app.run( manager );
app.run( boss );
}
void run( Worker worker ) {
System.out.println( worker.accept( visitor ) );
}
}