Are additional constructors for standard containers allowed?

Discussion in 'C++' started by Alf P. Steinbach /Usenet, Sep 3, 2010.

  1. With MSVC 10.0

    std::bitset<32>( 666u )

    does not compile. Apparently due to an extra constructor taking 'int' argument.
    Is that allowed by the standard?



    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, Sep 3, 2010
    #1
    1. Advertising

  2. On 9/3/2010 7:37 AM, Alf P. Steinbach /Usenet wrote:
    > With MSVC 10.0
    >
    > std::bitset<32>( 666u )
    >
    > does not compile. Apparently due to an extra constructor taking 'int'
    > argument. Is that allowed by the standard?


    I haven't found any wording in the Standard *prohibiting* any C++
    Standard Library implementor from supplying more functionality than
    specified in the Standard, like more c-tors, extra member functions,
    etc. Of course, if code that would otherwise be legal becomes
    ill-formed when those new parts are added, it becomes QoI issue.
    Complain to the vendor.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Sep 3, 2010
    #2
    1. Advertising

  3. Alf P. Steinbach /Usenet wrote:

    > With MSVC 10.0
    >
    > std::bitset<32>( 666u )
    >
    > does not compile. Apparently due to an extra constructor taking 'int'
    > argument. Is that allowed by the standard?
    >


    Just like adding template parameters to a template is disallowed (even if
    all of them have defaults) because it makes valid code invalid, this one
    would be invalid aswell, i think. Haven't got any chap/verse though.
    Johannes Schaub (litb), Sep 3, 2010
    #3
  4. On 3 sep, 16:29, Victor Bazarov <> wrote:
    > On 9/3/2010 7:37 AM, Alf P. Steinbach /Usenet wrote:
    >
    > > With MSVC 10.0

    >
    > > std::bitset<32>( 666u )

    >
    > > does not compile. Apparently due to an extra constructor taking 'int'
    > > argument. Is that allowed by the standard?

    >
    > I haven't found any wording in the Standard *prohibiting* any C++
    > Standard Library implementor from supplying more functionality than
    > specified in the Standard, like more c-tors, extra member functions,
    > etc.  Of course, if code that would otherwise be legal becomes
    > ill-formed when those new parts are added, it becomes QoI issue.
    > Complain to the vendor.


    IMHO clause 1.4/3 allows it:
    "For classes and class templates, the library clauses specify partial
    definitions.[...]"

    But there is a tension with clause 1.4/8:
    "A conforming implementation may have extensions, provided they do not
    alter the behavior of any well-formed program.[...]"

    Which mean that if a program is well formed according to the standard,
    it should be well formed according to a compliant implementation
    (which, I guess, is the purpose of a standard).

    IMO, since std::bitset<32>( 666u ) is well formed thanks to integral
    promotion, a compiler refusing it should be non-conformant.

    Apart from that, it is sometimes useful like implementations of
    std::string class that declare a private constructor taking a boolean
    in order to avoid integral promotion of std::string(false).

    --
    Michael
    Michael Doubez, Sep 3, 2010
    #4
  5. Alf P. Steinbach wrote:
    > With MSVC 10.0
    > std::bitset<32>( 666u )
    > does not compile. Apparently due to an extra constructor taking 'int'
    > argument. Is that allowed by the standard?


    Victor Bazarov wrote:
    > [...] Of course, if code that would otherwise be legal becomes
    > ill-formed when those new parts are added, it becomes QoI issue.
    > Complain to the vendor.


    This issue has been reported already, by Richard Webb: "Problems
    constructing a bitset from an unsigned long in the VC RC",
    http://connect.microsoft.com/VisualStudio/feedback/details/532897

    The extra contructor bitset(int) was there to fix another issue, by jkolb1,
    "bitset<5> bits(0) fails with conflict between longlong and char*",
    http://connect.microsoft.com/VisualStudio/feedback/details/500122

    Which is submitted as Standard Library issue #1325, by Christopher
    Jefferson: http://www.open-std.org/JTC1/sc22/WG21/docs/lwg-active.html#1325


    HTH,

    Niels
    --
    Niels Dekker
    http://www.xs4all.nl/~nd/dekkerware
    Scientific programmer at LKEB, Leiden University Medical Center
    Niels Dekker - no reply address, Sep 3, 2010
    #5
  6. * Niels Dekker - no reply address, on 03.09.2010 19:20:
    > Alf P. Steinbach wrote:
    >> With MSVC 10.0
    >> std::bitset<32>( 666u )
    >> does not compile. Apparently due to an extra constructor taking 'int'
    >> argument. Is that allowed by the standard?

    >
    > Victor Bazarov wrote:
    >> [...] Of course, if code that would otherwise be legal becomes
    >> ill-formed when those new parts are added, it becomes QoI issue.
    >> Complain to the vendor.

    >
    > This issue has been reported already, by Richard Webb: "Problems
    > constructing a bitset from an unsigned long in the VC RC",
    > http://connect.microsoft.com/VisualStudio/feedback/details/532897
    >
    > The extra contructor bitset(int) was there to fix another issue, by jkolb1,
    > "bitset<5> bits(0) fails with conflict between longlong and char*",
    > http://connect.microsoft.com/VisualStudio/feedback/details/500122
    >
    > Which is submitted as Standard Library issue #1325, by Christopher
    > Jefferson: http://www.open-std.org/JTC1/sc22/WG21/docs/lwg-active.html#1325


    Oh my. SNAFU strikes again. :)

    From the proposed resolution,

    <code>
    template <class charT>
    explicit
    bitset(const charT *str,
    typename basic_string<charT>::size_type pos = 0,
    typename basic_string<charT>::size_type n =
    basic_string<charT>::npos,
    charT zero = charT('0'), charT one = charT('1'));
    </code>

    Here charT('0') is not formally guaranteed to represent L'0' when charT is wchar_t.

    Of course it works for Unicode, when the original character set isn't EBCDIC.

    Oh holy Odin! And Tor! That ungood cast is actually in the C++0x draft!

    If only the committee made a habit of consulting me every time they got an urge
    to introduce fancy over-engineered "solutions". But no. Never heard from them.

    Anyways, if anyone of them should happen to listen in, the Correct(TM) thing to
    do is to /ditch/ that over-engineering -- a hammer does not need to also be a
    radio receiver and refrigerator, d'u hear? -- and is otherwise exemplified by


    <code>
    #include <locale>
    #include <iostream>

    template< class CharT >
    int foo( CharT c = std::use_facet< std::ctype< char > >( std::locale::classic()
    ).widen( '0' ) )
    {
    return c;
    }

    int main()
    {
    std::cout << foo<wchar_t>() << std::endl;
    }
    </code>


    <deadpan>This clear and concise code is why I love the standard lib's
    localization handling.</deadpan>

    But oops, this does not compile with MSVC 10.0... :-(


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, Sep 3, 2010
    #6
  7. Niels Dekker - no reply address <> wrote:
    > The extra contructor bitset(int) was there to fix another issue, by jkolb1,
    > "bitset<5> bits(0) fails with conflict between longlong and char*",


    One could argue that giving 0 as parameter to the std::bitset
    constructor makes little sense. As a char* it would be invalid and
    cause UB, and as an unsigned long it would be the same as not giving
    anything at all (because the default constructor initializes all the
    bits to zero already).

    I can't think of a rational situation where one would end up giving
    the *literal* 0 to the bitset constructor (giving it a an integral
    variable, possibly a const, wouldn't cause a problem because its type
    is unambiguous).

    Maybe if one #defines the initial value of the bitset as a preprocessor
    macro... Still feels a bit contrived, though.
    Juha Nieminen, Sep 3, 2010
    #7
  8. >> The extra contructor bitset(int) was there to fix another issue, by
    >> jkolb1, "bitset<5> bits(0) fails with conflict between longlong and
    >> char*",


    Juha Nieminen wrote:
    > One could argue that giving 0 as parameter to the std::bitset
    > constructor makes little sense. As a char* it would be invalid and
    > cause UB, and as an unsigned long it would be the same as not giving
    > anything at all (because the default constructor initializes all the
    > bits to zero already).
    >
    > I can't think of a rational situation where one would end up giving
    > the *literal* 0 to the bitset constructor (giving it a an integral
    > variable, possibly a const, wouldn't cause a problem because its type
    > is unambiguous).


    What do you mean by "possibly a const"? The following is still
    ambiguous, according to the current Working Draft (N3126):

    const int zeroConst = 0;
    // bitset(unsigned long long) or bitset(const char*)?
    std::bitset<5> bits(zeroConst);

    > Maybe if one #defines the initial value of the bitset as a
    > preprocessor macro... Still feels a bit contrived, though.


    I have to admit I originally didn't take this use case very serious,
    passing a zero-valued constant expression as constructor argument to
    std::bitset. But then I realized again, that backward compatibility is
    *very* important to C++. And the use case is entirely legal in C++03.
    Compilers don't even warn you against it!

    So I think LWG issue #1325 ("bitset") needs to be fixed.


    Kind regards, Niels
    --
    Niels Dekker
    http://www.xs4all.nl/~nd/dekkerware
    Scientific programmer at LKEB, Leiden University Medical Center
    Niels Dekker - no reply address, Sep 3, 2010
    #8
  9. Alf P. Steinbach /Usenet

    Pavel Guest

    Juha Nieminen wrote:
    > Niels Dekker - no reply address<> wrote:
    >> The extra contructor bitset(int) was there to fix another issue, by jkolb1,
    >> "bitset<5> bits(0) fails with conflict between longlong and char*",

    >
    > One could argue that giving 0 as parameter to the std::bitset
    > constructor makes little sense. As a char* it would be invalid and
    > cause UB, and as an unsigned long it would be the same as not giving
    > anything at all (because the default constructor initializes all the
    > bits to zero already).
    >
    > I can't think of a rational situation where one would end up giving
    > the *literal* 0 to the bitset constructor

    To initialize a static member of a class template specialization?

    For a bitset, you could do = std::bitset(), of course but (0) is shorter.

    -Pavel


    > (giving it a an integral
    > variable, possibly a const, wouldn't cause a problem because its type
    > is unambiguous).
    >
    > Maybe if one #defines the initial value of the bitset as a preprocessor
    > macro... Still feels a bit contrived, though.
    Pavel, Sep 4, 2010
    #9
  10. Alf P. Steinbach /Usenet

    joe Guest

    Alf P. Steinbach /Usenet wrote:>

    "Are additional constructors for standard containers allowed?"

    I hope not.
    joe, Sep 5, 2010
    #10
  11. Pavel wrote:
    > Juha Nieminen wrote:
    >> I can't think of a rational situation where one would end up
    >> giving the *literal* 0 to the bitset constructor

    > To initialize a static member of a class template specialization?
    >
    > For a bitset, you could do = std::bitset(), of course but (0) is
    > shorter.


    Thanks Pavel! I think that's a very convincing use case, especially in
    case of a default argument:

    int some_func( std::bitset<5> arg = 0 );

    But do you think "bitset<N> = NULL" should also compile?

    int some_func( std::bitset<5> arg = NULL ); // ???


    IMO the Standard does not need to specify whether "bitset<N> = NULL"
    compiles, but I certainly wouldn't appreciate undefined behavior!

    Kind regards,

    Niels
    --
    Niels Dekker
    http://www.xs4all.nl/~nd/dekkerware
    Scientific programmer at LKEB, Leiden University Medical Center
    Niels Dekker - no reply address, Sep 5, 2010
    #11
  12. Niels Dekker - no reply address wrote:

    > Pavel wrote:
    >> Juha Nieminen wrote:
    >>> I can't think of a rational situation where one would end up
    >>> giving the *literal* 0 to the bitset constructor

    >> To initialize a static member of a class template specialization?
    >>
    >> For a bitset, you could do = std::bitset(), of course but (0) is
    >> shorter.

    >
    > Thanks Pavel! I think that's a very convincing use case, especially in
    > case of a default argument:
    >
    > int some_func( std::bitset<5> arg = 0 );
    >
    > But do you think "bitset<N> = NULL" should also compile?
    >
    > int some_func( std::bitset<5> arg = NULL ); // ???
    >
    >
    > IMO the Standard does not need to specify whether "bitset<N> = NULL"
    > compiles, but I certainly wouldn't appreciate undefined behavior!
    >


    For a standard std::bitset<>, using "= NULL" certainly compiles because all
    integer types are convertible to unsigned long. But I don't see why you
    would use NULL instead of plain 0.

    Initializing a static member of an explicit class template specialization
    can be done by just letting the default constructor execute without an
    explicit initializer in case of 0. The case where you need an explicit
    initializer is only when you specialize the static member itself.
    Johannes Schaub (litb), Sep 5, 2010
    #12
  13. >> But do you think "bitset<N> = NULL" should also compile?
    >> int some_func( std::bitset<5> arg = NULL ); // ???


    Johannes Schaub (litb) wrote:
    > For a standard std::bitset<>, using "= NULL" certainly compiles
    > because all integer types are convertible to unsigned long.


    NULL does not need to be an integer, right? So I think "std::bitset<N>
    = NULL" does not need to compile, according to the C++03 Standard. But
    /if/ it compiles, it will pick the bitset(unsigned long) constructor,
    indeed. Constructing a bitset of all zero's, as people would expect.

    > But I don't see why you would use NULL instead of plain 0.


    Well, personally I certainly wouldn't pass NULL as constructor argument
    to std::bitset. But there might be some legacy code out here that does!

    It looks like acording to the latest Working Draft (N3126),
    std::bitset<N>(NULL) might trigger undefined behavior, right? Because
    NULL might be defined as nullptr, and std::bitset<N>(nullptr) would call
    the bitset(const char*) constructor from the Working Draft
    ([template.bitset]).

    Please correct me if I'm wrong!

    Kind regards, Niels
    --
    Niels Dekker
    http://www.xs4all.nl/~nd/dekkerware
    Scientific programmer at LKEB, Leiden University Medical Center
    Niels Dekker - no reply address, Sep 5, 2010
    #13
  14. Niels Dekker - no reply address wrote:

    >>> But do you think "bitset<N> = NULL" should also compile?
    >>> int some_func( std::bitset<5> arg = NULL ); // ???

    >
    > Johannes Schaub (litb) wrote:
    >> For a standard std::bitset<>, using "= NULL" certainly compiles
    >> because all integer types are convertible to unsigned long.

    >
    > NULL does not need to be an integer, right? So I think "std::bitset<N>
    > = NULL" does not need to compile, according to the C++03 Standard. But
    > /if/ it compiles, it will pick the bitset(unsigned long) constructor,
    > indeed. Constructing a bitset of all zero's, as people would expect.
    >


    In C++03, NULL is guaranteed to be an integer, so it guarantees compilation.
    Seems that C++0x would indeed not guarantee this anymore, though.

    >> But I don't see why you would use NULL instead of plain 0.

    >
    > Well, personally I certainly wouldn't pass NULL as constructor argument
    > to std::bitset. But there might be some legacy code out here that does!
    >
    > It looks like acording to the latest Working Draft (N3126),
    > std::bitset<N>(NULL) might trigger undefined behavior, right? Because
    > NULL might be defined as nullptr, and std::bitset<N>(nullptr) would call
    > the bitset(const char*) constructor from the Working Draft
    > ([template.bitset]).


    Exactly. I wasn't thinking about C++0x, but it seems that nullptr is a valid
    choice, and would make it take the const char* one. The workaround they
    thought of in that one issue report to template it and make it take "CharT
    const *" would get rid of that issue though.
    Johannes Schaub (litb), Sep 5, 2010
    #14
  15. Johannes Schaub (litb) wrote:
    > Niels Dekker - no reply address wrote:
    >> NULL does not need to be an integer, right? So I think
    >> "std::bitset<N> = NULL" does not need to compile, according to
    >> the C++03 Standard.

    >
    > In C++03, NULL is guaranteed to be an integer, so it guarantees
    > compilation.


    Okay, you're right (My bad!)

    >> It looks like acording to the latest Working Draft (N3126),
    >> std::bitset<N>(NULL) might trigger undefined behavior, right? Because
    >> NULL might be defined as nullptr, and std::bitset<N>(nullptr) would
    >> call the bitset(const char*) constructor from the Working Draft
    >> ([template.bitset]).

    >
    > Exactly. I wasn't thinking about C++0x, but it seems that nullptr is
    > a valid choice, and would make it take the const char* one. The
    > workaround they thought of in that one issue report to template it
    > and make it take "CharT const *" would get rid of that issue though.


    Hope you like the proposed resolution :)
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3133.html#1325


    Kind regards, Niels
    --
    Niels Dekker
    http://www.xs4all.nl/~nd/dekkerware
    Scientific programmer at LKEB, Leiden University Medical Center
    Niels Dekker - no reply address, Sep 5, 2010
    #15
  16. * Johannes Schaub (litb), on 05.09.2010 15:56:
    > Niels Dekker - no reply address wrote:
    >
    >>>> But do you think "bitset<N> = NULL" should also compile?
    >>>> int some_func( std::bitset<5> arg = NULL ); // ???

    >>
    >> Johannes Schaub (litb) wrote:
    >>> For a standard std::bitset<>, using "= NULL" certainly compiles
    >>> because all integer types are convertible to unsigned long.

    >>
    >> NULL does not need to be an integer, right? So I think "std::bitset<N>
    >> = NULL" does not need to compile, according to the C++03 Standard. But
    >> /if/ it compiles, it will pick the bitset(unsigned long) constructor,
    >> indeed. Constructing a bitset of all zero's, as people would expect.
    >>

    >
    > In C++03, NULL is guaranteed to be an integer, so it guarantees compilation.
    > Seems that C++0x would indeed not guarantee this anymore, though.
    >
    >>> But I don't see why you would use NULL instead of plain 0.

    >>
    >> Well, personally I certainly wouldn't pass NULL as constructor argument
    >> to std::bitset. But there might be some legacy code out here that does!
    >>
    >> It looks like acording to the latest Working Draft (N3126),
    >> std::bitset<N>(NULL) might trigger undefined behavior, right? Because
    >> NULL might be defined as nullptr, and std::bitset<N>(nullptr) would call
    >> the bitset(const char*) constructor from the Working Draft
    >> ([template.bitset]).

    >
    > Exactly. I wasn't thinking about C++0x, but it seems that nullptr is a valid
    > choice, and would make it take the const char* one. The workaround they
    > thought of in that one issue report to template it and make it take "CharT
    > const *" would get rid of that issue though.


    Sorry, no.

    <code>
    #include <iostream>
    #include <cstddef> // nullptr_t
    using namespace std;

    void foo( unsigned long long x )
    {
    cout << "f(" << x << ")" << endl;
    }

    // void foo( nullptr_t )
    // {
    // cout << "nullptr: "; foo( static_cast<unsigned long long>( 0 ) );
    // }

    template< class CharType >
    void foo( CharType const* s )
    {
    wcout << "f(\"" << s << "\")" << endl;
    }

    int main()
    {
    foo( 42 );
    foo( 0 );
    foo( nullptr );
    foo( "Blah" );
    }
    </code>

    <error>
    y.cpp(25) : error C2664: 'void foo(unsigned __int64)' : cannot convert parameter
    1 from 'nullptr' to 'unsigned __int64'
    A native nullptr can only be converted to bool or, using
    reinterpret_cast, to an integral type
    </error>


    Uncommenting the nulltr_t argument overload yields a different error,


    <error>
    y.cpp(24) : error C2668: 'foo' : ambiguous call to overloaded function
    y.cpp(10): could be 'void foo(std::nullptr_t)'
    y.cpp(5): or 'void foo(unsigned __int64)'
    while trying to match the argument list '(int)'
    </error>


    One solution if one wants to support nullptr as actual argument is to treat a
    literal 0 and 'nullptr' as the same, denoting 0, e.g.


    <code>
    #include <iostream>
    #include <cstddef> // nullptr_t
    using namespace std;

    template< typename Type >
    class Wrapped
    {
    private:
    Type value_;
    public:
    Wrapped( Type const& v ): value_( v ) {}
    Type& value() { return value_; }
    Type const& value() const { return value_; }
    };

    void foo( Wrapped<unsigned long long> x )
    {
    cout << "f(" << x.value() << ")" << endl;
    }

    void foo( nullptr_t )
    {
    cout << "nullptr: "; foo( Wrapped<unsigned long long>( 0 ) );
    }

    template< class CharType >
    void foo( CharType const* s )
    {
    wcout << "f(\"" << s << "\")" << endl;
    }

    int main()
    {
    foo( 42 );
    foo( 0 );
    foo( nullptr );
    foo( "Blah" );
    }
    </code>

    <output>
    f(42)
    nullptr: f(0)
    nullptr: f(0)
    f("Blah")
    </output>


    But I'm more concerned about the incorrect casts in the current draft, and in
    the proposed resolution of the 0-argument issue, than support of nullptr.

    It's sort of very blatant, with std::endl doing it right and std::bitset doing
    it wrong. If one argues that std::bitset casts are OK, then std::endl is
    needlessly doing a widening. But I don't think the argument that std::endl is
    defined with unneded complexity, holds, or if it does, it should be cleaned...


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, Sep 5, 2010
    #16
  17. * Niels Dekker -> Johannes Schaub, on 05.09.2010 18:03:
    >
    > Hope you like the proposed resolution :)
    > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3133.html#1325


    No. It doesn't support NULL as nullptr_t, and it has incorrect casts. See my
    reply to Johannes close else-thread, or for that matter my earlier posting.


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, Sep 5, 2010
    #17
  18. Alf P. Steinbach /Usenet wrote:

    > * Johannes Schaub (litb), on 05.09.2010 15:56:
    >> Niels Dekker - no reply address wrote:
    >>
    >>>>> But do you think "bitset<N> = NULL" should also compile?
    >>>>> int some_func( std::bitset<5> arg = NULL ); // ???
    >>>
    >>> Johannes Schaub (litb) wrote:
    >>>> For a standard std::bitset<>, using "= NULL" certainly compiles
    >>>> because all integer types are convertible to unsigned long.
    >>>
    >>> NULL does not need to be an integer, right? So I think "std::bitset<N>
    >>> = NULL" does not need to compile, according to the C++03 Standard. But
    >>> /if/ it compiles, it will pick the bitset(unsigned long) constructor,
    >>> indeed. Constructing a bitset of all zero's, as people would expect.
    >>>

    >>
    >> In C++03, NULL is guaranteed to be an integer, so it guarantees
    >> compilation. Seems that C++0x would indeed not guarantee this anymore,
    >> though.
    >>
    >>>> But I don't see why you would use NULL instead of plain 0.
    >>>
    >>> Well, personally I certainly wouldn't pass NULL as constructor argument
    >>> to std::bitset. But there might be some legacy code out here that does!
    >>>
    >>> It looks like acording to the latest Working Draft (N3126),
    >>> std::bitset<N>(NULL) might trigger undefined behavior, right? Because
    >>> NULL might be defined as nullptr, and std::bitset<N>(nullptr) would call
    >>> the bitset(const char*) constructor from the Working Draft
    >>> ([template.bitset]).

    >>
    >> Exactly. I wasn't thinking about C++0x, but it seems that nullptr is a
    >> valid choice, and would make it take the const char* one. The workaround
    >> they thought of in that one issue report to template it and make it take
    >> "CharT const *" would get rid of that issue though.

    >
    > Sorry, no.
    >


    Oh, my statement "would get rid of that issue" meant to say that it will
    fail to compile with the proposed solution. E.g that it won't silently work
    and select the "char const*" version if one passes nullptr.

    >
    > Uncommenting the nulltr_t argument overload yields a different error,
    >
    >
    > <error>
    > y.cpp(24) : error C2668: 'foo' : ambiguous call to overloaded function
    > y.cpp(10): could be 'void foo(std::nullptr_t)'
    > y.cpp(5): or 'void foo(unsigned __int64)'
    > while trying to match the argument list '(int)'
    > </error>
    >


    This looks to me like an ugly overload resolution behavior :( I wonder what
    the rationale is to allow "integer -> nullptr" ?

    >
    >
    > But I'm more concerned about the incorrect casts in the current draft, and
    > in the proposed resolution of the 0-argument issue, than support of
    > nullptr.
    >
    > It's sort of very blatant, with std::endl doing it right and std::bitset
    > doing it wrong. If one argues that std::bitset casts are OK, then
    > std::endl is needlessly doing a widening. But I don't think the argument
    > that std::endl is defined with unneded complexity, holds, or if it does,
    > it should be cleaned...
    >


    I don't understand how "std::endl" is connected to this and what 0-argument
    issue the proposed resolution has. I thought that resolution *fixes* it than
    causing it in the first place? I feel like I'm missing something, could you
    please elaborate?
    Johannes Schaub (litb), Sep 5, 2010
    #18
  19. * Johannes Schaub (litb), on 05.09.2010 19:13:
    > Alf P. Steinbach /Usenet wrote:
    >
    >> * Johannes Schaub (litb), on 05.09.2010 15:56:
    >>> Niels Dekker - no reply address wrote:
    >>>
    >>>>>> But do you think "bitset<N> = NULL" should also compile?
    >>>>>> int some_func( std::bitset<5> arg = NULL ); // ???
    >>>>
    >>>> Johannes Schaub (litb) wrote:
    >>>>> For a standard std::bitset<>, using "= NULL" certainly compiles
    >>>>> because all integer types are convertible to unsigned long.
    >>>>
    >>>> NULL does not need to be an integer, right? So I think "std::bitset<N>
    >>>> = NULL" does not need to compile, according to the C++03 Standard. But
    >>>> /if/ it compiles, it will pick the bitset(unsigned long) constructor,
    >>>> indeed. Constructing a bitset of all zero's, as people would expect.
    >>>>
    >>>
    >>> In C++03, NULL is guaranteed to be an integer, so it guarantees
    >>> compilation. Seems that C++0x would indeed not guarantee this anymore,
    >>> though.
    >>>
    >>>>> But I don't see why you would use NULL instead of plain 0.
    >>>>
    >>>> Well, personally I certainly wouldn't pass NULL as constructor argument
    >>>> to std::bitset. But there might be some legacy code out here that does!
    >>>>
    >>>> It looks like acording to the latest Working Draft (N3126),
    >>>> std::bitset<N>(NULL) might trigger undefined behavior, right? Because
    >>>> NULL might be defined as nullptr, and std::bitset<N>(nullptr) would call
    >>>> the bitset(const char*) constructor from the Working Draft
    >>>> ([template.bitset]).
    >>>
    >>> Exactly. I wasn't thinking about C++0x, but it seems that nullptr is a
    >>> valid choice, and would make it take the const char* one. The workaround
    >>> they thought of in that one issue report to template it and make it take
    >>> "CharT const *" would get rid of that issue though.

    >>
    >> Sorry, no.
    >>

    >
    > Oh, my statement "would get rid of that issue" meant to say that it will
    > fail to compile with the proposed solution. E.g that it won't silently work
    > and select the "char const*" version if one passes nullptr.


    Ah well, then it might break old C++98 code using NULL as argument.

    Anyway it wouldn't support that.


    >> Uncommenting the nulltr_t argument overload yields a different error,
    >>
    >>
    >> <error>
    >> y.cpp(24) : error C2668: 'foo' : ambiguous call to overloaded function
    >> y.cpp(10): could be 'void foo(std::nullptr_t)'
    >> y.cpp(5): or 'void foo(unsigned __int64)'
    >> while trying to match the argument list '(int)'
    >> </error>
    >>

    >
    > This looks to me like an ugly overload resolution behavior :( I wonder what
    > the rationale is to allow "integer -> nullptr" ?


    The same as for integral constant 0 -> null pointer of any type?

    ;-)


    >> But I'm more concerned about the incorrect casts in the current draft, and
    >> in the proposed resolution of the 0-argument issue, than support of
    >> nullptr.
    >>
    >> It's sort of very blatant, with std::endl doing it right and std::bitset
    >> doing it wrong. If one argues that std::bitset casts are OK, then
    >> std::endl is needlessly doing a widening. But I don't think the argument
    >> that std::endl is defined with unneded complexity, holds, or if it does,
    >> it should be cleaned...
    >>

    >
    > I don't understand how "std::endl" is connected to this and what 0-argument
    > issue the proposed resolution has. I thought that resolution *fixes* it than
    > causing it in the first place? I feel like I'm missing something, could you
    > please elaborate?


    Yes, the proposed resolution fixes one 0-argument issue.

    ---

    Unrelated to your question (as I interpret it), there is an additional such
    issue that it does not fix, namely the one raised by Niels Dekker upthread, that

    std::bitset<N> x( NULL );

    should perhaps better not be broken, when NULL is of std::nullptr_t.

    ---

    Regarding 'std::endl', its effect is defined as

    "Calls os.put(os.widen('\n')), then os.flush()"

    Assuming EBCDIC as narrow execution character set '\n' probably resolves to
    char(37). For the wchar_t instantiation of endl the call to 'widen' then
    converts that to char(10), the ASCII, Latin-1 and Unicode linefeed/newline.

    Which is OK.

    In the current draft's std::bitset (I'm using N3092), and also in the proposed
    resolution of the 0 issue, one constructor has defaulted arguments

    "charT zero=charT('0'), charT one=charT('1')"

    With EBCDIC narrow character set, '0' resolves to char( 240 ). For the wchar_t
    instantiation of the constructor the first cast then produces wchar_t( 240 ).
    Assuming Unicode wide character set that's an 'Eth' character, 'ð'.

    Which is not OK.


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, Sep 5, 2010
    #19
  20. Alf P. Steinbach /Usenet wrote:

    > * Johannes Schaub (litb), on 05.09.2010 19:13:
    >> Alf P. Steinbach /Usenet wrote:
    >>> But I'm more concerned about the incorrect casts in the current draft,
    >>> and in the proposed resolution of the 0-argument issue, than support of
    >>> nullptr.
    >>>
    >>> It's sort of very blatant, with std::endl doing it right and std::bitset
    >>> doing it wrong. If one argues that std::bitset casts are OK, then
    >>> std::endl is needlessly doing a widening. But I don't think the argument
    >>> that std::endl is defined with unneded complexity, holds, or if it does,
    >>> it should be cleaned...
    >>>

    >>
    >> I don't understand how "std::endl" is connected to this and what
    >> 0-argument issue the proposed resolution has. I thought that resolution
    >> *fixes* it than causing it in the first place? I feel like I'm missing
    >> something, could you please elaborate?

    >
    > Yes, the proposed resolution fixes one 0-argument issue.
    >
    > ---
    >
    > Unrelated to your question (as I interpret it), there is an additional
    > such issue that it does not fix, namely the one raised by Niels Dekker
    > upthread, that
    >
    > std::bitset<N> x( NULL );
    >
    > should perhaps better not be broken, when NULL is of std::nullptr_t.
    >


    I wonder how many people have written such code and how much code uses such
    code. Such code seems to make it hard to modernize stuff :(

    > ---
    >
    > Regarding 'std::endl', its effect is defined as
    >
    > "Calls os.put(os.widen('\n')), then os.flush()"
    >
    > Assuming EBCDIC as narrow execution character set '\n' probably resolves
    > to char(37). For the wchar_t instantiation of endl the call to 'widen'
    > then converts that to char(10), the ASCII, Latin-1 and Unicode
    > linefeed/newline.
    >
    > Which is OK.
    >
    > In the current draft's std::bitset (I'm using N3092), and also in the
    > proposed resolution of the 0 issue, one constructor has defaulted
    > arguments
    >
    > "charT zero=charT('0'), charT one=charT('1')"
    >
    > With EBCDIC narrow character set, '0' resolves to char( 240 ). For the
    > wchar_t instantiation of the constructor the first cast then produces
    > wchar_t( 240 ). Assuming Unicode wide character set that's an 'Eth'
    > character, 'ð'.
    >
    > Which is not OK.
    >


    Ahh thanks for these insights.
    Johannes Schaub (litb), Sep 5, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. velthuijsen
    Replies:
    3
    Views:
    5,291
    velthuijsen
    Feb 13, 2004
  2. TheReckter
    Replies:
    8
    Views:
    1,626
    Default User
    Oct 9, 2006
  3. Replies:
    7
    Views:
    534
    Pete Becker
    Jan 25, 2008
  4. Iñaki Baz Castillo
    Replies:
    13
    Views:
    476
    Iñaki Baz Castillo
    May 1, 2011
  5. Sebastian Mach
    Replies:
    5
    Views:
    301
Loading...

Share This Page