Reputation: 3951
I am implementing a visitor in order to use it with the boost variant library.
I want to know if is correct to specialize boost::static_visitor<>
with a const reference type.
Note my question here is the following:
There are any problem specializing boost::static_visitor<>
to 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.
}
};
Upvotes: 3
Views: 380
Reputation: 46
What about this, is this neat?
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 ) );
}
}
Upvotes: 0
Reputation: 393174
There is no problem as long as you don't return a reference to a local/temporary.
Also, be sure to check the validity of the reference over time (it ends when the variant object is destructed, which is when the variant itself is destructed, or (!) when it is reinitialized).
A variant contains an object of the "current" element type, and you can reference into that object perfectly fine. As long as the variant is not reinitialized to another element type (in which case the reference is "just" dangling, exactly like it would if the lifetime of the referred-to object had ended).
So if get_somet_t()
returns a T&
or T const&
(or something with a suitable implicit conversion) there is no problem.
In a simpler setting let me demonstrate valid options:
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
Likewise, you can even make variants of /just references/:
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
See it all Live On Coliru
Put yet another way, the following is fine:
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"
}
See it Live On Coliru as well.
Upvotes: 2