[variant] address of a variant type from the address of its sub-object?
Hi, Is there a portable way (guaranteed by the interface) to do the following? I have an object 'ob' of type Ob and know its address. I know it is an active sub-object of a variant type, where Ob is one of the sub-types. Is there a way to compute the address of the containing variant object? The problem I am solving is to how to access the whole variant object from inside a static visitor: ``` using VariantOb = boost::variant<Ob>; struct MyVisitor : boost::static_visitor<> { void operator()(Ob const& ob) const { // --> get the address of the variant object ? boost::addressof(ob) + what_offset; ?? } }; ``` Regards, &rzej
Andrzej Krzemienski wrote:
The problem I am solving is to how to access the whole variant object from inside a static visitor:
``` using VariantOb = boost::variant<Ob>;
struct MyVisitor : boost::static_visitor<> { void operator()(Ob const& ob) const
Can't you have struct MyVisitor { typedef void result_type; void operator()(Ob const& ob, Var const& var) const; }; and then pass bind( MyVisitor(), _1, ref(v) ) to visit?
2016-04-14 13:06 GMT+02:00 Peter Dimov
Andrzej Krzemienski wrote:
The problem I am solving is to how to access the whole variant object from inside a static visitor:
``` using VariantOb = boost::variant<Ob>;
struct MyVisitor : boost::static_visitor<> { void operator()(Ob const& ob) const
Can't you have
struct MyVisitor { typedef void result_type; void operator()(Ob const& ob, Var const& var) const; };
and then pass bind( MyVisitor(), _1, ref(v) ) to visit?
I suppose, I can. In fact, currently my visitor looks like this: ``` struct MyVisitor : boost::static_visitor<> { VariantOb const& v_; MyVisitor(VariantOb const& v) : v_(v) {} void operator()(Ob const& ob) const { boost::addressof(v_); } }; ``` But, I am trying to optimize a function that I believe is slower than ideal, and my hypothesis is that this carrying of the additional pointer around is the culprit. In order to confirm it, I need to be able to get the address of the containing variant object in flight and compare this to the current solution. Regards, &rzej
Andrzej Krzemienski wrote:
But, I am trying to optimize a function that I believe is slower than ideal, and my hypothesis is that this carrying of the additional pointer around is the culprit.
That's hard to believe. Copying a pointer should be insignificant compared to the cost of the dispatch. What does the profiler say? You should probably spell out the apply_visitor() call by hand inline; in addition to eliminating the pointer copy, this would allow you to experiment with, say, reordering the tests from most frequent to least frequent.
That's hard to believe. Copying a pointer should be insignificant compared to the cost of the dispatch. What does the profiler say?
Which compiler? I have found that MSVC is extremely pessimistic with this type of situation and generates unnecessary mov instructions for the pointer in the struct. You can confirm it, if your case is simple enough, by stepping through an inner loop to see if it's reloading that pointer over and over again, even though there are no instructions changing the pointer in that inner loop. -- chris
Chris Glover wrote:
That's hard to believe. Copying a pointer should be insignificant compared to the cost of the dispatch. What does the profiler say?
Which compiler? I have found that MSVC is extremely pessimistic with this type of situation and generates unnecessary mov instructions for the pointer in the struct.
It's inside a switch on the type index. A mov instruction or two shouldn't matter. The generated code should be something like switch( v.which() ) { case 0: my_visitor( get<T1>(v) ); break; case 1: my_visitor( get<T2>(v) ); break; // and so on } except with about seven layers of templates on top. I just don't see an extra pointer copy being of significance here. If the switch is compiled to a table you have an indirect jmp; if to a sequence of comparisons, would depend on how well they can be predicted.
2016-04-14 17:47 GMT+02:00 Peter Dimov
Chris Glover wrote:
That's hard to believe. Copying a pointer should be insignificant > compared to the cost of the dispatch. What does the profiler say?
Which compiler? I have found that MSVC is extremely pessimistic with this type of situation and generates unnecessary mov instructions for the pointer in the struct.
It's inside a switch on the type index. A mov instruction or two shouldn't matter. The generated code should be something like
switch( v.which() ) { case 0:
my_visitor( get<T1>(v) ); break;
case 1:
my_visitor( get<T2>(v) ); break;
// and so on }
except with about seven layers of templates on top. I just don't see an extra pointer copy being of significance here. If the switch is compiled to a table you have an indirect jmp; if to a sequence of comparisons, would depend on how well they can be predicted.
Thank you for putting it this way. Ultimately my goal is to compare two
ways of representing a (mathematical) expression tree. I tried one with
OO-based virtual dispatch:
```
struct AdditioNode : NodeInterface
{
unique_ptr<NodeInterface> leftSubexpression, rightSubexpression;
double eval() override;
};
// etc...
```
And storing variants in a vector and representing links to subnodes as
indexes:
```
struct Addition
{
int leftSubexpression, rightSubexpression;
};
using Node = variant
On 04/15/2016 03:10 AM, Andrzej Krzemienski wrote: [snip]
Thank you for putting it this way. Ultimately my goal is to compare two ways of representing a (mathematical) expression tree. I tried one with OO-based virtual dispatch:
``` struct AdditioNode : NodeInterface { unique_ptr<NodeInterface> leftSubexpression, rightSubexpression; double eval() override; }; // etc... ```
And storing variants in a vector and representing links to subnodes as indexes:
``` struct Addition { int leftSubexpression, rightSubexpression; };
using Node = variant
; using ExpressionTree = vector<Node>; ``` I haven't done any profiling yet, but my benchmarks show, the former one (with virtual interfaces) is about twice faster. I found it quite surprising.
Other people got similar surprising performance results: http://stackoverflow.com/questions/11906741/boost-variant-vs-virtual-interfa... -regards, Larry
On 14 Apr 2016 at 15:14, Chris Glover wrote:
That's hard to believe. Copying a pointer should be insignificant compared to the cost of the dispatch. What does the profiler say?
Which compiler? I have found that MSVC is extremely pessimistic with this type of situation and generates unnecessary mov instructions for the pointer in the struct. You can confirm it, if your case is simple enough, by stepping through an inner loop to see if it's reloading that pointer over and over again, even though there are no instructions changing the pointer in that inner loop.
MSVC doesn't do strict aliasing optimisation. Once upon a time it could via the /Oa switch, but that facility was removed as people's code broke. In your above use case I'd sprinkle some __restrict around. Should solve the problem. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
AMDG On 04/14/2016 12:39 AM, Andrzej Krzemienski wrote:
Hi, Is there a portable way (guaranteed by the interface) to do the following?
I have an object 'ob' of type Ob and know its address. I know it is an active sub-object of a variant type, where Ob is one of the sub-types. Is there a way to compute the address of the containing variant object?
No there isn't. It can't work in general because of http://www.boost.org/doc/html/variant/design.html#variant.design.never-empty... In Christ, Steven Watanabe
2016-04-14 16:30 GMT+02:00 Steven Watanabe
AMDG
On 04/14/2016 12:39 AM, Andrzej Krzemienski wrote:
Hi, Is there a portable way (guaranteed by the interface) to do the following?
I have an object 'ob' of type Ob and know its address. I know it is an active sub-object of a variant type, where Ob is one of the sub-types. Is there a way to compute the address of the containing variant object?
No there isn't. It can't work in general because of
http://www.boost.org/doc/html/variant/design.html#variant.design.never-empty...
In Christ, Steven Watanabe
Thanks. The case may be different for the TR's std::experimental::variant, though. I will have to try it. Regards, &rzej
participants (6)
-
Andrzej Krzemienski
-
Chris Glover
-
Larry Evans
-
Niall Douglas
-
Peter Dimov
-
Steven Watanabe