> But that is not the relevant pattern. What we require is the *joint*
> instantiation of A B and C types, and a dispatch that is specialized for
> this joint combination, and hence is as fast as possible.
The joint combination is straightforward:
template<class A, class B, class C>
void fooImpl(A a, B b, C c);
void foo(std::variant<A1..> avar,
std::variant<B1..> bvar,
std::variant<C1..> cvar)
{
std::visit(
[](auto a, auto b, auto c)
{
fooImpl(a, b, c);
},
avar, bvar, cvar);
}
but in this case, as you pointed out, we don't get much compile time
advantage - but we do still enjoy the fast dispatch.
> What you are describing (independent dispatching for every type) is not
> very different from dynamic typing, unless the code can be divided into
> clear disjoint blocks as in your example, which is not the case for most
> algorithms in graph-tool
I will defer to your judgment on that one, though perhaps surprisingly I
found this worked in the first (only) algorithm I tried applying it to:
assortativity.
I selected it based on how long it took to build. The results were:
boost::any + typelist : 177s, 4.5GB memory
std::variant for edge weights only: 37s + 1.74GB
The memory reduction is very useful in that it enables parallel builds.
The prototype can be found here:
https://git.skewed.de/jaafar/graph-tool/compare/master...feature%2Fvariant-conversion-demo
Best,
Jeff
On Thu, Feb 6, 2020 at 1:18 PM Tiago de Paula Peixoto <[email protected]>
wrote:
> Am 06.02.20 um 18:59 schrieb Jeff Trull:
> >> std::variant. The high compile times stem simply from the fact we have
> >> to cycle through the Cartesian product of the set of types of each
> >
> > I absolutely agree on that diagnosis, but I think std::variant can play
> > a role. The key
> > is to postpone dispatch, where possible, to refactor out one or more of
> > the product
> > terms.
> >
> > At the moment the dispatch mechanism identifies all the concrete types
> > first, /then/
> > runs the correct instantiated function. If there were more flexibility
> > in this process,
> > dispatching to selected type-dependent code could happen later and cover
> > less code.
> > Consider:
> >
> > template<class A, class B, class C>
> > void foo(A a, B b, C c)
> > {
> > // lots of A and B code
> > // a single use of C
> > // lots more A and B
> > }
> >
> > For the sake of a small amount of code involving C the entire function
> > gets rebuilt as
> > many times as there are C types. Now consider an approach that postponed
> > determining C's concrete type:
> >
> > template<class A, class B>
> > void foo(A a, B b, std::variant<C1, C2, ...> c_var)
> > {
> > // lots of A and B
> > std::visit([](auto const & c){ // use of C }, c_var);
> > // lots more A and B
> > }
> >
> > If C was something based on scalar_types this would mean a factor of 6
> > reduction in
> > instantiations!
>
> But that is not the relevant pattern. What we require is the *joint*
> instantiation of A B and C types, and a dispatch that is specialized for
> this joint combination, and hence is as fast as possible.
>
> What you are describing (independent dispatching for every type) is not
> very different from dynamic typing, unless the code can be divided into
> clear disjoint blocks as in your example, which is not the case for most
> algorithms in graph-tool.
>
> Best,
> Tiago
>
> --
> Tiago de Paula Peixoto <[email protected]>
> _______________________________________________
> graph-tool mailing list
> [email protected]
> https://lists.skewed.de/mailman/listinfo/graph-tool
>
_______________________________________________
graph-tool mailing list
[email protected]
https://lists.skewed.de/mailman/listinfo/graph-tool