[fusion] Illegal partial specialization error.

If I include <boost/fusion/support/tag_of.hpp> my compiler (derived from Metrowerks 9.4) gives me several errors claiming illegal partial specializations. It looks like it's partially specializing forward declarations of the tag_of structure. I don't know if that's allowed (from the error I assume probably not) but it certainly seems to be pointless to me. Are these perhaps supposed to be more than declarations? Thanks, Michael Marcin

Michael Marcin wrote:
If I include <boost/fusion/support/tag_of.hpp> my compiler (derived from Metrowerks 9.4) gives me several errors claiming illegal partial specializations.
It looks like it's partially specializing forward declarations of the tag_of structure. I don't know if that's allowed (from the error I assume probably not) but it certainly seems to be pointless to me. Are these perhaps supposed to be more than declarations?
What's the point, if you (partially) specialize it anyway ? FWIW, I have seen similar errors with IBM's XLC++ and am pretty sure that at least in that particular case it was a compiler bug. Regards, Stefan -- ...ich hab' noch einen Koffer in Berlin...

Stefan Seefeld wrote:
Michael Marcin wrote:
If I include <boost/fusion/support/tag_of.hpp> my compiler (derived from Metrowerks 9.4) gives me several errors claiming illegal partial specializations.
It looks like it's partially specializing forward declarations of the tag_of structure. I don't know if that's allowed (from the error I assume probably not) but it certainly seems to be pointless to me. Are these perhaps supposed to be more than declarations?
What's the point, if you (partially) specialize it anyway ?
FWIW, I have seen similar errors with IBM's XLC++ and am pretty sure that at least in that particular case it was a compiler bug.
Yes, it's most probably a compiler bug. I've seen this before. patch welcome ;-). I do not have CW now. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Stefan Seefeld wrote:
Michael Marcin wrote:
If I include <boost/fusion/support/tag_of.hpp> my compiler (derived from Metrowerks 9.4) gives me several errors claiming illegal partial specializations.
It looks like it's partially specializing forward declarations of the tag_of structure. I don't know if that's allowed (from the error I assume probably not) but it certainly seems to be pointless to me. Are these perhaps supposed to be more than declarations? What's the point, if you (partially) specialize it anyway ?
FWIW, I have seen similar errors with IBM's XLC++ and am pretty sure that at least in that particular case it was a compiler bug.
Yes, it's most probably a compiler bug. I've seen this before. patch welcome ;-). I do not have CW now.
...and we gave up on XLC++ with our project. So no ideas about possible work-arounds from me either. Sorry. Stefan -- ...ich hab' noch einen Koffer in Berlin...

Stefan Seefeld wrote:
Joel de Guzman wrote:
Stefan Seefeld wrote:
Michael Marcin wrote:
If I include <boost/fusion/support/tag_of.hpp> my compiler (derived from Metrowerks 9.4) gives me several errors claiming illegal partial specializations.
It looks like it's partially specializing forward declarations of the tag_of structure. I don't know if that's allowed (from the error I assume probably not) but it certainly seems to be pointless to me. Are these perhaps supposed to be more than declarations? What's the point, if you (partially) specialize it anyway ?
FWIW, I have seen similar errors with IBM's XLC++ and am pretty sure that at least in that particular case it was a compiler bug.
Yes, it's most probably a compiler bug. I've seen this before. patch welcome ;-). I do not have CW now.
...and we gave up on XLC++ with our project. So no ideas about possible work-arounds from me either. Sorry.
I guess it's time for me to learn something new. What's the purpose of something like: template <typename T, std::size_t N> struct tag_of<boost::array<T, N> >; shouldn't it be something like: template <typename T, std::size_t N> struct tag_of<boost::array<T, N> > {}; or: struct adapted_fusion_tag; template <typename T, std::size_t N> struct tag_of<boost::array<T, N> > { typedef adapted_fusion_tag type; }; Or maybe I compeletly miss the point. Thanks, Michael Marcin

On Thu, 12 Apr 2007 11:46:03 -0500 "Michael Marcin" <mmarcin@method-solutions.com> wrote:
What's the purpose of something like:
template <typename T, std::size_t N> struct tag_of<boost::array<T, N> >;
It forward declares a template. The compiler now knows what to expect.
shouldn't it be something like:
template <typename T, std::size_t N> struct tag_of<boost::array<T, N> > {};
Now you have defined the template. All non specialized stucts tag_of will be defined as an empty class. By simply declaring it, the onus is now on another piece of code to properly define the template. Someone can still provide a "general" definition, but it's very possible that specializations are the true desire. If you want an empty stuct to be the default template, then you can use the above. If, however, you want to force the template definitions then simply provide the forward declaration. With the forward declaration, if a user tries to use the struct in a non-specialized way, a compiler error will result, which is good. You don't want the user to get default "nothing" behavior from a typo. Does that make any sense at all?

Jody Hagins wrote:
On Thu, 12 Apr 2007 11:46:03 -0500 "Michael Marcin" <mmarcin@method-solutions.com> wrote:
template <typename T, std::size_t N> struct tag_of<boost::array<T, N> > {};
Now you have defined the template. All non specialized stucts tag_of will be defined as an empty class. By simply declaring it, the onus is now on another piece of code to properly define the template. Someone can still provide a "general" definition, but it's very possible that specializations are the true desire.
If you want an empty stuct to be the default template, then you can use the above. If, however, you want to force the template definitions then simply provide the forward declaration.
With the forward declaration, if a user tries to use the struct in a non-specialized way, a compiler error will result, which is good. You don't want the user to get default "nothing" behavior from a typo.
Does that make any sense at all?
Maybe. IIUC what that forward declared partial specialization is doing is akin to saying: - I know the default implementation of tag_of can't be correct for boost::array<T,N> - There should be an implementation of tag_of that will make it work for boost::array<T,N> - I don't know what that implementation is, you or someone else better provide it Is it then true that when proper definition of the partial specialization is provided this partial specialization of the declaration has no effect whatsoever? If that is true and this is a compiler bug then perpahs we can use a configuration macro like BOOST_NO_DECLARTION_PARTIAL_SPECIALIZATION to simply omit these these forward declarations on compilers that choke on them (like CW 9.4 apparerently does). Thanks, Michael Marcin

Michael Marcin wrote:
Jody Hagins wrote:
Does that make any sense at all?
Maybe.
IIUC what that forward declared partial specialization is doing is akin to saying: - I know the default implementation of tag_of can't be correct for boost::array<T,N> - There should be an implementation of tag_of that will make it work for boost::array<T,N> - I don't know what that implementation is, you or someone else better provide it
Is it then true that when proper definition of the partial specialization is provided this partial specialization of the declaration has no effect whatsoever?
If that is true and this is a compiler bug then perpahs we can use a configuration macro like BOOST_NO_DECLARTION_PARTIAL_SPECIALIZATION to simply omit these these forward declarations on compilers that choke on them (like CW 9.4 apparerently does).
Or maybe I still don't understand. Are these forward declaration partial specializations strictly necessary? Thanks, Michael Marcin

Michael Marcin wrote:
Michael Marcin wrote:
Jody Hagins wrote:
Does that make any sense at all? Maybe.
IIUC what that forward declared partial specialization is doing is akin to saying: - I know the default implementation of tag_of can't be correct for boost::array<T,N> - There should be an implementation of tag_of that will make it work for boost::array<T,N> - I don't know what that implementation is, you or someone else better provide it
Is it then true that when proper definition of the partial specialization is provided this partial specialization of the declaration has no effect whatsoever?
If that is true and this is a compiler bug then perpahs we can use a configuration macro like BOOST_NO_DECLARTION_PARTIAL_SPECIALIZATION to simply omit these these forward declarations on compilers that choke on them (like CW 9.4 apparerently does).
Or maybe I still don't understand. Are these forward declaration partial specializations strictly necessary?
Yes. It's a means to prevent unwanted ODR violation. Fusion is modular. The support for boost::array comes when you include a header. Imagine a case where a TU does not include the header and another that does. Without the forward declaration, the second TU will pick up the default (non-specialized) implementation, which might or might not compile, but will certainly be a violation of ODR. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Michael Marcin wrote:
Or maybe I still don't understand. Are these forward declaration partial specializations strictly necessary?
Yes. It's a means to prevent unwanted ODR violation. Fusion is modular. The support for boost::array comes when you include a header. Imagine a case where a TU does not include the header and another that does. Without the forward declaration, the second TU will pick up the default (non-specialized) implementation, which might or might not compile, but will certainly be a violation of ODR.
Agreed. But we certainly need workarounds for compilers that can't handle an incomplete partial specialization. On head, xpressive doesn't compile on cw-9.4 because of this problem, and that's a regression from 1.34. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Joel de Guzman wrote:
Michael Marcin wrote:
Or maybe I still don't understand. Are these forward declaration partial specializations strictly necessary? Yes. It's a means to prevent unwanted ODR violation. Fusion is modular. The support for boost::array comes when you include a header. Imagine a case where a TU does not include the header and another that does. Without the forward declaration, the second TU will pick up the default (non-specialized) implementation, which might or might not compile, but will certainly be a violation of ODR.
Agreed. But we certainly need workarounds for compilers that can't handle an incomplete partial specialization. On head, xpressive doesn't compile on cw-9.4 because of this problem, and that's a regression from 1.34.
Agreed. I intend to go back to the Mac anyway, after a long trek into Wintel. Sorry if this may be OT but is virtualization really working well for developers? I'd love to get, say, VisualC++ along side CW. Also, is CW not a dead-end? It's a pity that they no longer have the Windows version. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Eric Niebler wrote:
Joel de Guzman wrote:
Or maybe I still don't understand. Are these forward declaration partial specializations strictly necessary? Yes. It's a means to prevent unwanted ODR violation. Fusion is modular. The support for boost::array comes when you include a
Michael Marcin wrote: header. Imagine a case where a TU does not include the header and another that does. Without the forward declaration, the second TU will pick up the default (non-specialized) implementation, which might or might not compile, but will certainly be a violation of ODR.
Agreed. But we certainly need workarounds for compilers that can't handle an incomplete partial specialization. On head, xpressive doesn't compile on cw-9.4 because of this problem, and that's a regression from 1.34.
Agreed. I intend to go back to the Mac anyway, after a long trek into Wintel. Sorry if this may be OT but is virtualization really working well for developers? I'd love to get, say, VisualC++ along side CW. Also, is CW not a dead-end? It's a pity that they no longer have the Windows version.
Nokia is using a CW9.4 Windows x86 compiler to build emulator applications for their Series 60 devices. Not sure if it can be used to build standalone x86 applications though. - Michael Marcin

Michael Marcin wrote:
IIUC what that forward declared partial specialization is doing is akin to saying: - I know the default implementation of tag_of can't be correct for boost::array<T,N> - There should be an implementation of tag_of that will make it work for boost::array<T,N> - I don't know what that implementation is, you or someone else better provide it
Yes. It's done to prevent (different kinds of) ODR violations. Example 1: template<typename T> struct X { }; template<typename T> struct Y { }; // [...] <--- 'X< Y<void> >' gets instantiated template<typename T> struct X< Y<void> > { // !!! ERROR, already defined }; Example 2: // first translation unit includes template<typename T> struct is_xyz : mpl::false_ { }; template<> struct is_xyz<void> : mpl::true_ { }; // now is_xyz<xyz>::value == true ---- // second translation unit misses to include the specialization template<typename T> struct is_xyz : mpl::false_ { }; // now is_xyz<xyz>::value == false Note there are compilers that happily compile and link example 2.
Is it then true that when proper definition of the partial specialization is provided this partial specialization of the declaration has no effect whatsoever?
Yes, once the type is completed it's complete ;-). It just prevents the type to be completed prematurely by instantiating the primary template.
If that is true and this is a compiler bug then perpahs we can use a configuration macro like BOOST_NO_DECLARTION_PARTIAL_SPECIALIZATION to simply omit these these forward declarations on compilers that choke on them (like CW 9.4 apparerently does).
Are you sure it only applies to /partial/ specializations? How about the full ones? My suggestions for the names would be: BOOST_NO_FORWARD_DECLARED_TEMPLATE_SPECIALIZATION or BOOST_NO_FORWARD_DECLARED_TEMPLATE_PARTIAL_SPECIALIZATION Regards, Tobias

Joel de Guzman wrote:
Stefan Seefeld wrote:
Michael Marcin wrote:
If I include <boost/fusion/support/tag_of.hpp> my compiler (derived from Metrowerks 9.4) gives me several errors claiming illegal partial specializations.
It looks like it's partially specializing forward declarations of the tag_of structure. I don't know if that's allowed (from the error I assume probably not) but it certainly seems to be pointless to me. Are these perhaps supposed to be more than declarations? What's the point, if you (partially) specialize it anyway ?
FWIW, I have seen similar errors with IBM's XLC++ and am pretty sure that at least in that particular case it was a compiler bug.
Yes, it's most probably a compiler bug. I've seen this before. patch welcome ;-). I do not have CW now.
The attached patch should fix this problem. It uses an MPL assert in the primary template to catch potential ODR violations, rather than forward declared partial specializations. HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com Index: tag_of.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/fusion/support/tag_of.hpp,v retrieving revision 1.7 diff -b -d -u -r1.7 tag_of.hpp --- tag_of.hpp 22 Mar 2007 19:21:29 -0000 1.7 +++ tag_of.hpp 2 Jul 2007 06:05:29 -0000 @@ -13,6 +13,7 @@ #include <boost/mpl/has_xxx.hpp> #include <boost/utility/enable_if.hpp> #include <boost/mpl/identity.hpp> +#include <boost/mpl/assert.hpp> #include <boost/mpl/bool.hpp> #include <boost/mpl/if.hpp> #include <utility> @@ -45,6 +46,39 @@ namespace detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(fusion_tag) + + template<typename Sequence> + struct is_specialized + : mpl::false_ + {}; + + template < + class T0, class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8, class T9 + > + struct is_specialized<tuples::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > + : mpl::true_ + {}; + + template <class Head, class Tail> + struct is_specialized<tuples::cons<Head, Tail> > + : mpl::true_ + {}; + + template <> + struct is_specialized<tuples::null_type> + : mpl::true_ + {}; + + template <typename T, std::size_t N> + struct is_specialized<boost::array<T, N> > + : mpl::true_ + {}; + + template<typename T1, typename T2> + struct is_specialized<std::pair<T1, T2> > + : mpl::true_ + {}; } namespace traits @@ -54,31 +88,15 @@ : mpl::if_< detail::is_mpl_sequence<Sequence>, mpl::identity<mpl_sequence_tag>, mpl::identity<non_fusion_tag> >::type - { }; + { + BOOST_MPL_ASSERT_NOT((detail::is_specialized<Sequence>)); + }; template <typename Sequence> struct tag_of<Sequence, typename boost::enable_if<detail::has_fusion_tag<Sequence> >::type> { typedef typename Sequence::fusion_tag type; }; - - template < - class T0, class T1, class T2, class T3, class T4, - class T5, class T6, class T7, class T8, class T9 - > - struct tag_of<tuples::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >; - - template <class Head, class Tail> - struct tag_of<tuples::cons<Head, Tail> >; - - template <> - struct tag_of<tuples::null_type>; - - template <typename T, std::size_t N> - struct tag_of<boost::array<T, N> >; - - template<typename T1, typename T2> - struct tag_of<std::pair<T1, T2> >; } namespace detail

Eric Niebler wrote:
Joel de Guzman wrote:
Stefan Seefeld wrote:
Michael Marcin wrote:
If I include <boost/fusion/support/tag_of.hpp> my compiler (derived from Metrowerks 9.4) gives me several errors claiming illegal partial specializations.
It looks like it's partially specializing forward declarations of the tag_of structure. I don't know if that's allowed (from the error I assume probably not) but it certainly seems to be pointless to me. Are these perhaps supposed to be more than declarations? What's the point, if you (partially) specialize it anyway ?
FWIW, I have seen similar errors with IBM's XLC++ and am pretty sure that at least in that particular case it was a compiler bug.
Yes, it's most probably a compiler bug. I've seen this before. patch welcome ;-). I do not have CW now.
The attached patch should fix this problem. It uses an MPL assert in the primary template to catch potential ODR violations, rather than forward declared partial specializations.
Cool! Committed to CVS? Thanks! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Eric Niebler wrote:
The attached patch should fix this problem. It uses an MPL assert in the primary template to catch potential ODR violations, rather than forward declared partial specializations.
Cool! Committed to CVS? Thanks!
Done. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Joel de Guzman wrote:
Eric Niebler wrote:
The attached patch should fix this problem. It uses an MPL assert in the primary template to catch potential ODR violations, rather than forward declared partial specializations. Cool! Committed to CVS? Thanks!
Done.
Echoes from the past. I'll give it a try when I get back from vacation. Thanks, Michael Marcin

Michael Marcin wrote:
Eric Niebler wrote:
Joel de Guzman wrote:
Eric Niebler wrote:
The attached patch should fix this problem. It uses an MPL assert in the primary template to catch potential ODR violations, rather than forward declared partial specializations. Cool! Committed to CVS? Thanks! Done.
Echoes from the past.
I'll give it a try when I get back from vacation.
Works great. Thanks Eric. - Michael Marcin
participants (7)
-
Eric Niebler
-
Jody Hagins
-
Joel de Guzman
-
Michael Marcin
-
Michael Marcin
-
Stefan Seefeld
-
Tobias Schwinger