[BGL] Visual Studio 12 finish_edge() failure, general BOOST_TTI_HAS_MEMBER_FUNCTION failure?

Hello boost! In the BGL, finish_edge() is a visitor function of DFS, but it is optional. It is made optional via BOOST_TTI_HAS_MEMBER_FUNCTION. Here's how BGL defines it: ------------- BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge) template <bool IsCallable> struct do_call_finish_edge { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis& vis, const E& e, const G& g) { vis.finish_edge(e, g); } }; template <> struct do_call_finish_edge<false> { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis&, const E&, const G&) {} }; template <typename E, typename G, typename Vis> void call_finish_edge(Vis& vis, const E& e, const G& g) { // Only call if method exists do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g); } ------------- In all my efforts, the Visual Studio 12 compiler fails to call finish_edge(). I've tried templated versions, direct versions, virtual versions, with and without const params, inline and not inline. In every case, VS says "code will not be hit, no executable code is associated with this line. possible causes: preprocessor directives or compiler/linker optimizations". I'm in debug mode with minimal optimizations, and there's no preprocessor wrapper. It's possible there's a problem with the way I'm calling it, but it happens when I use a simple example from another user. This ticket includes very simple sample code that should fire the finish_edge() function. It does not work for me using VS 12: https://svn.boost.org/trac/boost/ticket/9770 https://svn.boost.org/trac/boost/attachment/ticket/9770/test.cc I have a large project depending on the BGL, which has been great otherwise. I've coded a workaround by using the other non-optional visitor functions. But there are edge cases (sorry, no pun intended! ha) that fail with my workaround. The only possible solution is to get finish_edge() to fire. I'd like to do it the intended way, rather than rewrite BGL code to make finish_edge() non-optional. I'll go try this with a recent version of gcc now... Thanks for any input at all! Michael Behrns-Miller

On 3/31/2014 1:27 PM, Michael Behrns-Miller wrote:
Hello boost!
In the BGL, finish_edge() is a visitor function of DFS, but it is optional. It is made optional via BOOST_TTI_HAS_MEMBER_FUNCTION. Here's how BGL defines it:
-------------
BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
template <bool IsCallable> struct do_call_finish_edge { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis& vis, const E& e, const G& g) { vis.finish_edge(e, g); } };
template <> struct do_call_finish_edge<false> { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis&, const E&, const G&) {} };
template <typename E, typename G, typename Vis> void call_finish_edge(Vis& vis, const E& e, const G& g) { // Only call if method exists do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g); }
The invocation of has_member_function_finish_edge has to match the member function signature which you are invoking. If the member function signature for finish_edge is: void finish_edge(const E&, const G&); then your invocation for do_call_finish_edge must be: do_call_finish_edge < has_member_function_finish_edge < Vis, void, boost::mpl::vector < const E&, const G& > > ::value
::call_finish_edge(vis, e, g);
or do_call_finish_edge < has_member_function_finish_edge < void Vis::* (const E&,const G&) > ::value
::call_finish_edge(vis, e, g);

On 3/31/2014 6:30 PM, Edward Diener wrote:
On 3/31/2014 1:27 PM, Michael Behrns-Miller wrote:
... Here's how BGL defines it:
-------------
BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
template <bool IsCallable> struct do_call_finish_edge { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis& vis, const E& e, const G& g) { vis.finish_edge(e, g); } };
template <> struct do_call_finish_edge<false> { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis&, const E&, const G&) {} };
template <typename E, typename G, typename Vis> void call_finish_edge(Vis& vis, const E& e, const G& g) { // Only call if method exists do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g); }
The invocation of has_member_function_finish_edge has to match the member function signature which you are invoking. If the member function signature for finish_edge is:
void finish_edge(const E&, const G&);
then your invocation for do_call_finish_edge must be:
do_call_finish_edge < has_member_function_finish_edge < Vis, void, boost::mpl::vector < const E&, const G& > > ::value
::call_finish_edge(vis, e, g);
or
do_call_finish_edge < has_member_function_finish_edge < void Vis::* (const E&,const G&) > ::value
::call_finish_edge(vis, e, g);
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Thank you Edward. The instantiation code was not mine, that is what is done by the BGL, here: boost\graph\depth_first_search.hpp The instantiation code does not seem to match your recommendation. This simple DFS test fails: https://svn.boost.org/trac/boost/attachment/ticket/9770/test.cc So it sounds like BGL needs some patching to match your format. It should change from... do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g); to... do_call_finish_edge<has_member_function_finish_edge<void Vis::* (const E&,const G&)>::value>::call_finish_edge(vis, e, g); Does that sound correct?

On 4/1/2014 4:40 AM, Michael Behrns-Miller wrote:
On 3/31/2014 6:30 PM, Edward Diener wrote:
On 3/31/2014 1:27 PM, Michael Behrns-Miller wrote:
... Here's how BGL defines it:
-------------
BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
template <bool IsCallable> struct do_call_finish_edge { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis& vis, const E& e, const G& g) { vis.finish_edge(e, g); } };
template <> struct do_call_finish_edge<false> { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis&, const E&, const G&) {} };
template <typename E, typename G, typename Vis> void call_finish_edge(Vis& vis, const E& e, const G& g) { // Only call if method exists do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g); }
The invocation of has_member_function_finish_edge has to match the member function signature which you are invoking. If the member function signature for finish_edge is:
void finish_edge(const E&, const G&);
then your invocation for do_call_finish_edge must be:
do_call_finish_edge < has_member_function_finish_edge < Vis, void, boost::mpl::vector < const E&, const G& > > ::value
::call_finish_edge(vis, e, g);
or
do_call_finish_edge < has_member_function_finish_edge < void Vis::* (const E&,const G&) > ::value
::call_finish_edge(vis, e, g);
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Thank you Edward.
The instantiation code was not mine, that is what is done by the BGL, here:
boost\graph\depth_first_search.hpp
The instantiation code does not seem to match your recommendation. This simple DFS test fails:
https://svn.boost.org/trac/boost/attachment/ticket/9770/test.cc
So it sounds like BGL needs some patching to match your format. It should change from...
do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g);
to...
do_call_finish_edge<has_member_function_finish_edge<void Vis::* (const E&,const G&)>::value>::call_finish_edge(vis, e, g);
Does that sound correct?
On the newer code, Visual Studio 12 gives me: boost_1_55_0/boost/graph/depth_first_search.hpp(86): error C2182: 'abstract declarator' : illegal use of type 'void'

On 4/1/2014 4:50 AM, Michael Behrns-Miller wrote:
On 4/1/2014 4:40 AM, Michael Behrns-Miller wrote:
On 3/31/2014 6:30 PM, Edward Diener wrote:
On 3/31/2014 1:27 PM, Michael Behrns-Miller wrote:
... Here's how BGL defines it:
-------------
BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
template <bool IsCallable> struct do_call_finish_edge { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis& vis, const E& e, const G& g) { vis.finish_edge(e, g); } };
template <> struct do_call_finish_edge<false> { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis&, const E&, const G&) {} };
template <typename E, typename G, typename Vis> void call_finish_edge(Vis& vis, const E& e, const G& g) { // Only call if method exists do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g); }
The invocation of has_member_function_finish_edge has to match the member function signature which you are invoking. If the member function signature for finish_edge is:
void finish_edge(const E&, const G&);
then your invocation for do_call_finish_edge must be:
do_call_finish_edge < has_member_function_finish_edge < Vis, void, boost::mpl::vector < const E&, const G& > > ::value
::call_finish_edge(vis, e, g);
or
do_call_finish_edge < has_member_function_finish_edge < void Vis::* (const E&,const G&) > ::value
::call_finish_edge(vis, e, g);
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Thank you Edward.
The instantiation code was not mine, that is what is done by the BGL, here:
boost\graph\depth_first_search.hpp
The instantiation code does not seem to match your recommendation. This simple DFS test fails:
https://svn.boost.org/trac/boost/attachment/ticket/9770/test.cc
So it sounds like BGL needs some patching to match your format. It should change from...
do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g);
to...
do_call_finish_edge<has_member_function_finish_edge<void Vis::* (const E&,const G&)>::value>::call_finish_edge(vis, e, g);
Does that sound correct?
On the newer code, Visual Studio 12 gives me:
boost_1_55_0/boost/graph/depth_first_search.hpp(86): error C2182: 'abstract declarator' : illegal use of type 'void'
I am the developer for TTI. In your test case the actual VIZ struct has templated member functions, so I do not think has_member_function will find your templated functions. TTI is a compile-time mechanism for producing compile-time code. But even if it does not find the member functions at compile-time TTI should not produce a compile-time error so I definitely want to look at this situation. As to why Visual Studio 12 gives that error I need to be able to reproduce your compile steps. I am an absolute novice with the Boost graph library. I think I need to build the library first, then run your test against it. Jeremiah Willcock produced the changes in graph using TTI so he may have had a very good reason for using the original has_member_function signature, although it looks wrong to me on purely a TTI basis. Hopefully he will chime in on his change.

On 4/1/2014 8:45 AM, Edward Diener wrote:
On 4/1/2014 4:50 AM, Michael Behrns-Miller wrote:
On 4/1/2014 4:40 AM, Michael Behrns-Miller wrote:
On 3/31/2014 6:30 PM, Edward Diener wrote:
On 3/31/2014 1:27 PM, Michael Behrns-Miller wrote:
... Here's how BGL defines it:
-------------
BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
template <bool IsCallable> struct do_call_finish_edge { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis& vis, const E& e, const G& g) { vis.finish_edge(e, g); } };
template <> struct do_call_finish_edge<false> { template <typename E, typename G, typename Vis> static void call_finish_edge(Vis&, const E&, const G&) {} };
template <typename E, typename G, typename Vis> void call_finish_edge(Vis& vis, const E& e, const G& g) { // Only call if method exists do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g); }
The invocation of has_member_function_finish_edge has to match the member function signature which you are invoking. If the member function signature for finish_edge is:
void finish_edge(const E&, const G&);
then your invocation for do_call_finish_edge must be:
do_call_finish_edge < has_member_function_finish_edge < Vis, void, boost::mpl::vector < const E&, const G& > > ::value
::call_finish_edge(vis, e, g);
or
do_call_finish_edge < has_member_function_finish_edge < void Vis::* (const E&,const G&) > ::value
::call_finish_edge(vis, e, g);
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Thank you Edward.
The instantiation code was not mine, that is what is done by the BGL, here:
boost\graph\depth_first_search.hpp
The instantiation code does not seem to match your recommendation. This simple DFS test fails:
https://svn.boost.org/trac/boost/attachment/ticket/9770/test.cc
So it sounds like BGL needs some patching to match your format. It should change from...
do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g);
to...
do_call_finish_edge<has_member_function_finish_edge<void Vis::* (const E&,const G&)>::value>::call_finish_edge(vis, e, g);
Does that sound correct?
On the newer code, Visual Studio 12 gives me:
boost_1_55_0/boost/graph/depth_first_search.hpp(86): error C2182: 'abstract declarator' : illegal use of type 'void'
I am the developer for TTI. In your test case the actual VIZ struct has templated member functions, so I do not think has_member_function will find your templated functions. TTI is a compile-time mechanism for producing compile-time code. But even if it does not find the member functions at compile-time TTI should not produce a compile-time error so I definitely want to look at this situation.
As to why Visual Studio 12 gives that error I need to be able to reproduce your compile steps. I am an absolute novice with the Boost graph library. I think I need to build the library first, then run your test against it.
Jeremiah Willcock produced the changes in graph using TTI so he may have had a very good reason for using the original has_member_function signature, although it looks wrong to me on purely a TTI basis. Hopefully he will chime in on his change.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Thanks Edward, appreciate the feedback, I'll be monitoring. In the meantime my workaround of making finish_edge() non-optional is working for me. But of course I'd prefer not to have to change boost code before using. :-) Sure appreciate all you guys do to develop and maintain the libraries, boost is just fantastic.
participants (2)
-
Edward Diener
-
Michael Behrns-Miller