Re: class static constants, mpl, and linker problems

Daniel Krügler <dsp@bdal.de> writes:
- Assumption one: Boost does not provide the definitions of potential static constants hidden by the BOOST_STATIC_CONSTANT definition (I used only the headers of the library, so my potential testing bug would be that I had to include the corresponding translation units of boost providing the constant's definitions, but sorry - I did not find them!).
In general BOOST_STATIC_CONSTANT is used within templates, so the definition of a corresponding member may be given in the header file: template <int N> struct int_ { BOOST_STATIC_CONSTANT(int, value = N); }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION template <int N> int const int_<N>::value; #endif
As I said: If this assumption is false, please blame me straight for incomplete testing and for trying to spread bad rumors on this (really!) great library.
It's probably not false in most cases.
- Assumption two: Even if Boost does provide these definitions, there may occur problems due to the VC7.1 flags /Za and /Ze (aka disabling and enabling language extensions), which I will explain in the following. The same point applies as to assumptions one, if I did incomplete testing or testing with rather old boost libraries.
The nasty thing concerning the /Ze flag is that it effectively does not "extend" the language in every case. A small testing case is the following program:
a.h: ------------------------- #ifndef A_H_INC #define A_H_INC struct A { static const int val = 42; // Declaration of a static member variable }; #endif -------------------------
a.cpp -------------------- #include "a.h" const int A::val; // Definition might be needed, if the program accesses // the adress of A::val -------------------------
main.cpp -------------------- #include "a.h" int main() { } -------------------------
Although this is a C++ Standard compliant program, it will not successfully link with the /Ze flag enabled, which is to my opion a real compiler bug (which I already posted to m.p.v.language, but got no reasonable response yet). The obtained error message is:
error LNK2005: "private: static int const A::val" (?val@A@@0HB) already defined in a.obj error LNK2005: "private: static int const A::val" (?val@A@@0HB) already defined in main.obj
Looks like a bug to me.
Question: Is this special deficiency of the VC7.1 compiler taken account in the current boost library?
I doubt it. How would we do that?
I think, it is impossible to demand, that users are enforced to use either only /Ze or only /Za, because each of these choices has some considerable drawbacks (at least on Windows systems...)
Well, it seems to me that we can only respond to actual problems. Do you have an actual case of using a Boost library where these issues cause you trouble? -- Dave Abrahams Boost Consulting www.boost-consulting.com

Hello, David, David Abrahams schrieb:
Daniel Krügler <dsp@bdal.de> writes:
- Assumption one: Boost does not provide the definitions of potential static constants hidden by the BOOST_STATIC_CONSTANT definition (I used only the headers of the library, so my potential testing bug would be that I had to include the corresponding translation units of boost providing the constant's definitions, but sorry - I did not find them!).
[snip]
As I said: If this assumption is false, please blame me straight for incomplete testing and for trying to spread bad rumors on this (really!) great library.
It's probably not false in most cases.
Thanks for this answer, Dave.
- Assumption two: Even if Boost does provide these definitions, there may occur problems due to the VC7.1 flags /Za and /Ze (aka disabling and enabling language extensions), which I will explain in the following. The same point applies as to assumptions one, if I did incomplete testing or testing with rather old boost libraries.
The nasty thing concerning the /Ze flag is that it effectively does not "extend" the language in every case. A small testing case is the following program:
[snip]
Looks like a bug to me.
Then we are two, at least. Thanks for your opinion.
Question: Is this special deficiency of the VC7.1 compiler taken account in the current boost library?
I doubt it. How would we do that?
I don't know. I hope, that there might exist a similar solution as to the wchar_t problem (have a look at the thread "ICC wchar_t proposed solution"), which takes advantage of a compiler macro _WCHAR_T_DEFINED to do the right thing. Whether a similar #define exists for the /Za and /Ze option, I don't know. Is anyone aware of this? A view into the compiler help was not very convincing. The remark "..and automatically defines the __STDC__ predefined macro for C programs" seems not very helpful for C++ programs.
Well, it seems to me that we can only respond to actual problems. Do you have an actual case of using a Boost library where these issues cause you trouble?
A contrived example for the first issue was given in my original posting. I repeat it here again: --------------------------------------------------------------- #include <boost/mpl/vector.hpp> #include <boost/mpl/size.hpp> void foo(const long&) { } int main() { typedef boost::mpl::vector<char, double> MyTypeContainer; typedef boost::mpl::size<MyTypeContainer> MPSizeType; foo(MPSizeType::value); } --------------------------------------------------------------- Switch to /Za, if you use the VC7.1, the mentioned mingw compiler will choke anyway. The second problem would result **iff** boost provides the missing definitions of boost::mpl::size<>::value and similar. In this case the VC7.1 compiler would choke similarily (but fortuneatly not the mingw compiler any longer), if instead of the /Za flag the complimentary /Ze flag is set :-(( Greetings, Daniel

Daniel Krügler <dsp@bdal.de> writes:
A contrived example for the first issue was given in my original posting. I repeat it here again: --------------------------------------------------------------- #include <boost/mpl/vector.hpp> #include <boost/mpl/size.hpp>
void foo(const long&) { }
int main() { typedef boost::mpl::vector<char, double> MyTypeContainer; typedef boost::mpl::size<MyTypeContainer> MPSizeType;
foo(MPSizeType::value); } ---------------------------------------------------------------
Switch to /Za, if you use the VC7.1, the mentioned mingw compiler will choke anyway.
I don't understand the assertion. What does mingw have to do with vc7.1
The second problem would result **iff** boost provides the missing definitions of boost::mpl::size<>::value and similar. In this case the VC7.1 compiler would choke similarily (but fortuneatly not the mingw compiler any longer), if instead of the /Za flag the complimentary /Ze flag is set :-((
Hmm. I'm very surprised. It appears that when /Za is supplied, *nothing* you can do will cause an integral static const member to be instantiated, and when /Za is not supplied, an out-of-line definition makes no difference because it's not needed. Furthermore, according to the MS docs, the compiler supplies no preprocessor symbol we could use to detect /Za and switch to using enums. I'm not sure there's a workaround for this one. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Furthermore, according to the MS docs, the compiler supplies no preprocessor symbol we could use to detect /Za and switch to using enums. I'm not sure there's a workaround for this one.
I think _MSC_EXTENSIONS is the preprocessor symbol you're looking for. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler schrieb:
David Abrahams wrote:
Furthermore, according to the MS docs, the compiler supplies no preprocessor symbol we could use to detect /Za and switch to using enums. I'm not sure there's a workaround for this one.
I think _MSC_EXTENSIONS is the preprocessor symbol you're looking for.
Great, Eric! Interestingly this hint was not provided in the corresponding help of VC7.1 or I was looking to hasty again... Thank you very much, Daniel

David Abrahams schrieb:
Daniel Krügler <dsp@bdal.de> writes:
A contrived example for the first issue was given in my original posting. I repeat it here again: --------------------------------------------------------------- #include <boost/mpl/vector.hpp> #include <boost/mpl/size.hpp>
void foo(const long&) { }
int main() { typedef boost::mpl::vector<char, double> MyTypeContainer; typedef boost::mpl::size<MyTypeContainer> MPSizeType;
foo(MPSizeType::value); } ---------------------------------------------------------------
Switch to /Za, if you use the VC7.1, the mentioned mingw compiler will choke anyway.
I don't understand the assertion. What does mingw have to do with vc7.1
Nothing. I just wanted to provide another strongly conforming compiler, which shows the predicted linker errors.
The second problem would result **iff** boost provides the missing definitions of boost::mpl::size<>::value and similar. In this case the VC7.1 compiler would choke similarily (but fortuneatly not the mingw compiler any longer), if instead of the /Za flag the complimentary /Ze flag is set :-((
Hmm. I'm very surprised. It appears that when /Za is supplied, *nothing* you can do will cause an integral static const member to be instantiated, and when /Za is not supplied, an out-of-line definition makes no difference because it's not needed. Furthermore, according to the MS docs, the compiler supplies no preprocessor symbol we could use to detect /Za and switch to using enums. I'm not sure there's a workaround for this one.
I am quite sure, that your interpretation of the meaning of /Za and /Ze is not sufficient. /Za disables language extensions and makes the linker choking on missing definitions of in-class static constant members, which were initialized in the class-definition, but nowhere defined, and were used in expressions where their addresses are necessary. That behaviour is what we both understand as C++ compliant behaviour. /Ze enables language extensions and does not make the corresponding definition necessary (that is fine for me and I understand that as an extension), **but** it chokes on duplicate definitions, if the conforming definition is provided (that is not fine for me). According to Eric, we seem to have chance by taking advantage of the _MSC_EXTENSIONS flag - these are good news! Thank you for your thorough answers and your patience concerning my rashly conclusions, Daniel

Daniel Krügler <dsp@bdal.de> writes:
According to Eric, we seem to have chance by taking advantage of the _MSC_EXTENSIONS flag - these are good news!
Thank you for your thorough answers and your patience concerning my rashly conclusions,
Aleksey and I would be very grateful if you'd post a patch to boost/mpl/aux_/integral_wrapper.hpp that solves these problems. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams schrieb:
Daniel Krügler <dsp@bdal.de> writes:
According to Eric, we seem to have chance by taking advantage of the _MSC_EXTENSIONS flag - these are good news!
Thank you for your thorough answers and your patience concerning my rashly conclusions,
Aleksey and I would be very grateful if you'd post a patch to boost/mpl/aux_/integral_wrapper.hpp that solves these problems.
Sorry for my late answer, Dave. Actually I was not so sure whether your response was a kind of joke (due to my enthusiastic "[..] we seem to have chance by[..]") or not;-) But I took it as honest as possible and searched for the definition(s) of any of the definitions of those static "value" members declared in any of the (macro hidden) AUX_WRAPPER_NAME classes. Regrettably I didn't find any of these definitions in my 1.30.0 or in the last official 1.30.2 release. Can someone give me a pointer, where these definitions can be found? Thanks, Daniel

Daniel Krügler <dsp@bdal.de> writes:
David Abrahams schrieb:
Daniel Krügler <dsp@bdal.de> writes:
According to Eric, we seem to have chance by taking advantage of the _MSC_EXTENSIONS flag - these are good news!
Thank you for your thorough answers and your patience concerning my rashly conclusions, Aleksey and I would be very grateful if you'd post a patch to boost/mpl/aux_/integral_wrapper.hpp that solves these problems. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sorry for my late answer, Dave. Actually I was not so sure whether your response was a kind of joke (due to my enthusiastic "[..] we seem to have chance by[..]") or not;-)
Not.
But I took it as honest as possible and searched for the definition(s) of any of the definitions of those static "value" members declared in any of the (macro hidden) AUX_WRAPPER_NAME classes. Regrettably I didn't find any of these definitions in my 1.30.0 or in the last official 1.30.2 release. Can someone give me a pointer, where these definitions can be found?
I pointed you at the file above. Please use a CVS snapshot or the release candidate for the basis of your patch 1.30.x is very different. -- Dave Abrahams Boost Consulting www.boost-consulting.com

But I took it as honest as possible and searched for the definition(s) of any of the definitions of those static "value" members declared in any of the (macro hidden) AUX_WRAPPER_NAME classes. Regrettably I didn't find any of these definitions in my 1.30.0 or in the last official 1.30.2 release. Can someone give me a pointer, where these definitions can be found?
I pointed you at the file above. Please use a CVS snapshot or the release candidate for the basis of your patch 1.30.x is very different.
Thanks for that hint, Dave. I took the last officially available files and found one **further** MSVC7.1 bug concerning static data members - sigh! (I posted the problems some minutes ago to the m.s.v.c. news group) The following program causes a linker error using the /Za flag (disable language extensions): b.h: ------------------------- #ifndef B_H_INC #define B_H_INC template <typename T> struct B { static const int val = 123; }; template <typename T> const int B<T>::val; // Definition provided, but not recognized... #endif ------------------------- main.cpp -------------------- #include "b.h" void foo(const int&) { } int main() { typedef B<double> MyB; foo(MyB::val); }------------------------- I could verify, that the same kind of linker error occurs for boost sources, if a program accesses the address of constant static data member of integral/enumeration type of any template class. Currently I have not found any workaround for this, despite the provocative proposal to add in the configuration file /boost/config/compiler/visualc.hpp the following lines: #if (_MSC_VER <= 1310) && !defined(_MSC_EXTENSIONS) # define BOOST_NO_INCLASS_MEMBER_INITIALIZATION #endif Can someone support or deny these awful observations??? Some further informations regarding my personal tests: The corresponding data member definition is recognized, if the in-class initialization is changed to an out-of-class initialization, which obviously makes these kind of constants not suitable as part of usual ICE's.... Daniel
participants (3)
-
Daniel Krügler
-
David Abrahams
-
Eric Niebler