Changes between Initial Version and Version 1 of Guidelines/Borland


Ignore:
Timestamp:
Feb 14, 2010, 12:21:08 PM (13 years ago)
Author:
Daniel James
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Guidelines/Borland

    v1 v1  
     1[[PageOutline]]
     2
     3= Portability Hints: Borland C++ 5.5.1 = #intro
     4
     5It is a general aim for boost libraries to be
     6[wiki:Guidelines/Requirements#Portability portable]. The
     7primary means for achieving this goal is to adhere to ISO
     8Standard C++. However, ISO C++ is a broad and complex standard
     9and most compilers are not fully conformant to ISO C++ yet. In
     10order to achieve portability in the light of this restriction,
     11it seems advisable to get acquainted with those language
     12features that some compilers do not fully implement yet.
     13
     14This page gives portability hints on some language features
     15of the Borland C++ version 5.5.1 compiler. Furthermore, the
     16appendix presents additional problems with Borland C++ version
     175.5. Borland C++ 5.5.1 is a freely available command-line
     18compiler for Win32 available at http://www.borland.com/.
     19
     20Each entry in the following list describes a particular
     21issue, complete with sample source code to demonstrate the
     22effect. Most sample code herein has been verified to compile
     23with gcc 2.95.2 and Comeau C++ 4.2.44.
     24
     25== Preprocessor symbol == #preprocessor
     26
     27The preprocessor symbol `__BORLANDC__` is defined
     28for all Borland C++ compilers. Its value is the version number
     29of the compiler interpreted as a hexadecimal number. The
     30following table lists some known values.
     31
     32||Compiler                 ||`__BORLANDC__` value||
     33||Borland C++ Builder 4    ||0x0540              ||
     34||Borland C++ Builder 5    ||0x0550              ||
     35||Borland C++ 5.5          ||0x0550              ||
     36||Borland C++ 5.5.1        ||0x0551              ||
     37||Borland C++ Builder 6    ||0x0560              ||
     38
     39== Core Language == #core
     40
     41=== [using-directive] Mixing `using`-declarations and `using`-directives === #using-directive
     42
     43Mixing `using`-directives (which refer to whole
     44namespaces) and namespace-level `using`-declarations
     45(which refer to individual identifiers within foreign
     46namespaces) causes ambiguities where there are none. The
     47following code fragment illustrates this:
     48{{{
     49namespace N {
     50    int x();
     51}
     52
     53using N::x;
     54using namespace N;
     55
     56int main()
     57{
     58    &x;     // Ambiguous overload
     59}
     60}}}
     61
     62=== [using template] `using`-declarations for class templates === #using-template
     63
     64Identifiers for class templates can be used as arguments to
     65`using`-declarations as any other identifier.
     66However, the following code fails to compile with Borland
     67C++:
     68{{{
     69template<class T>
     70class X { };
     71
     72namespace N
     73{
     74    // "cannot use template 'X<T>' without specifying specialization parameters"
     75    using ::X;
     76};
     77}}}
     78
     79=== [template const arg] Deduction of constant arguments to function templates === #template-const-arg
     80
     81Template function type deduction should omit top-level
     82constness. However, this code fragment instantiates "f<const int>(int)":
     83{{{
     84template<class T>
     85void f(T x)
     86{
     87    x = 1;  // works
     88    (void) &x;
     89    T y = 17;
     90    y = 20;  // "Cannot modify a const object in function f<const int>(int)"
     91    (void) &y;
     92}
     93
     94int main()
     95{
     96    const int i = 17;
     97    f(i);
     98}
     99}}}
     100
     101=== [function address] Resolving addresses of overloaded functions === #function-address
     102
     103Addresses of overloaded functions are not in all contexts
     104properly resolved (std:13.4 [over.over]); here is a small
     105example:
     106{{{
     107template<class Arg>
     108void f( void(*g)(Arg) );
     109
     110void h(int);
     111void h(double);
     112
     113template<class T>
     114void h2(T);
     115
     116int main()
     117{
     118    void (*p)(int) = h;            // this works (std:13.4-1.1)
     119    void (*p2)(unsigned char) = h2;    // this works as well (std:13.4-1.1)
     120    f<int>(h2);  // this also works (std:13.4-1.3)
     121   
     122    // "Cannot generate template specialization from h(int)",
     123    // "Could not find a match for f<Arg>(void (*)(int))"
     124    f<double>(h);   // should work (std:13.4-1.3)
     125   
     126    f( (void(*)(double))h);  // C-style cast works (std:13.4-1.6 with 5.4)
     127   
     128    // "Overloaded 'h' ambiguous in this context"
     129    f(static_cast<void(*)(double)>(h)); // should work (std:13.4-1.6 with 5.2.9)
     130}
     131}}}
     132
     133'''Workaround:''' Always use C-style casts when
     134determining addresses of (potentially) overloaded
     135functions.
     136
     137=== [string conversion] Converting `const char *` to `std::string` === #string-conversion
     138
     139Implicitly converting `const char *` parameters
     140to `std::string` arguments fails if template
     141functions are explicitly instantiated (it works in the usual
     142cases, though):
     143{{{
     144#include <string>
     145
     146template<class T>
     147void f(const std::string & s)
     148{}
     149
     150int main()
     151{
     152    f<double>("hello");  // "Could not find a match for f<T>(char *)"
     153}
     154
     155}}}
     156
     157'''Workaround:''' Avoid explicit template
     158function instantiations (they have significant problems with
     159Microsoft Visual C++) and pass default-constructed unused dummy
     160arguments with the appropriate type. Alternatively, if you wish
     161to keep to the explicit instantiation, you could use an
     162explicit conversion to `std::string` or declare the
     163template function as taking a `const char *`
     164parameter.
     165
     166=== [template value defaults] Dependent default arguments for template value parameters === #template-value-defaults
     167
     168Template value parameters which default to an expression
     169dependent on previous template parameters don't work:
     170{{{
     171template<class T>
     172struct A
     173{
     174    static const bool value = true;
     175};
     176
     177// "Templates must be classes or functions", "Declaration syntax error"
     178template<class T, bool v = A<T>::value>
     179struct B {};
     180
     181int main()
     182{
     183    B<int> x;
     184}
     185}}}
     186
     187'''Workaround:''' If the relevant non-type
     188template parameter is an implementation detail, use inheritance
     189and a fully qualified identifier (for example,
     190::N::A<T>::value).
     191
     192=== [function partial ordering] Partial ordering of function templates === #function-partial-ordering
     193
     194Partial ordering of function templates, as described in
     195std:14.5.5.2 [temp.func.order], does not work:
     196{{{
     197#include <iostream>
     198
     199template<class T> struct A {};
     200
     201template<class T1>
     202void f(const A<T1> &)
     203{
     204    std::cout << "f(const A<T1>&)\n";
     205}
     206
     207template<class T>
     208void f(T)
     209{
     210    std::cout << "f(T)\n";
     211}
     212
     213int main()
     214{
     215    A<double> a;
     216    f(a);   // output: f(T)  (wrong)
     217    f(1);   // output: f(T)  (correct)
     218}
     219}}}
     220
     221'''Workaround:''' Declare all such functions
     222uniformly as either taking a value or a reference
     223parameter.
     224
     225=== [instantiate memfun ptr] Instantiation with member function pointer === #instantiate-memfun-ptr
     226
     227When directly instantiating a template with some member
     228function pointer, which is itself dependent on some template
     229parameter, the compiler cannot cope:
     230
     231{{{
     232template<class U> class C { };
     233template<class T>
     234class A
     235{
     236    static const int v = C<void (T::*)()>::value;
     237};
     238}}}
     239
     240'''Workaround:''' Use an intermediate `typedef`:
     241{{{
     242template<class U> class C { };
     243template<class T>
     244class A
     245{
     246    typedef void (T::*my_type)();
     247    static const int v = C<my_type>::value;
     248};
     249}}}
     250
     251(Extracted from e-mail exchange of David Abrahams, Fernando
     252Cacciola, and Peter Dimov; not actually tested.)
     253
     254== Library == #library
     255
     256=== [cmath.abs] Function `double std::abs(double)` missing === #cmath-abs
     257
     258The function `double std::abs(double)` should be
     259defined (std:26.5-5 [lib.c.math]), but it is not:
     260{{{
     261#include <cmath>
     262
     263int main()
     264{
     265    double (*p)(double) = std::abs;  // error
     266}
     267}}}
     268
     269Note that `int std::abs(int)` will be used
     270without warning if you write `std::abs(5.1)`.
     271
     272Similar remarks apply to seemingly all of the other standard
     273math functions, where Borland C++ fails to provide
     274`float` and `long double` overloads.
     275
     276'''Workaround:''' Use `std::fabs` instead if type genericity is not required.
     277
     278== Appendix: Additional issues with Borland C++ version 5.5 == #5.5-issues
     279
     280These issues are documented mainly for historic reasons. If
     281you are still using Borland C++ version 5.5, you are strongly
     282encouraged to obtain an upgrade to version 5.5.1, which fixes
     283the issues described in this section.
     284
     285=== [inline friend] Inline friend functions in template classes === #inline-friend
     286
     287If a friend function of some class has not been declared
     288before the friend function declaration, the function is
     289declared at the namespace scope surrounding the class
     290definition. Together with class templates and inline
     291definitions of friend functions, the code in the following
     292fragment should declare (and define) a non-template function
     293"bool N::f(int,int)", which is a friend of class
     294N::A<int>. However, Borland C++ v5.5 expects the function
     295f to be declared beforehand:
     296{{{
     297namespace N {
     298    template<class T>
     299    class A
     300    {
     301        // "f is not a member of 'N' in function main()"
     302        friend bool f(T x, T y) { return x < y; }
     303    };
     304}
     305
     306int main()
     307{
     308    N::A<int> a;
     309}
     310}}}
     311
     312This technique is extensively used in boost/operators.hpp.
     313Giving in to the wish of the compiler doesn't work in this
     314case, because then the "instantiate one template, get lots of
     315helper functions at namespace scope" approach doesn't work
     316anymore. Defining BOOST_NO_OPERATORS_IN_NAMESPACE (a define
     317BOOST_NO_INLINE_FRIENDS_IN_CLASS_TEMPLATES would match this
     318case better) works around this problem and leads to another
     319one, see [using-template].