Topic: make_pair (2rd episode)


Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/08/04
Raw View
The following apparently innocuous expression:

    make_pair ("a", 1)

 (i)  doesn't compile

 (ii) even if it did, has the unnatural
      type pair<const char[2], int>

I count five reasons:

 (1) "a" has type const char [2], not const char*

 (2) std::make_pair takes its deduced arguments by reference

 (3) deduced reference arguments don't have the trivial
     conversions (array-to-pointer or function-to-pointer)

 (4) innitialisation of an array member by the
     construtor-argument-list isn't allowed

 (5) std::make_pair does direct innitialisation via the
     constructor

To make the code compile, at least one these must go.

Of course, the best change is the one that:

 (a) is conceptually simpler

 (b) requires the least changes in the standard

 (c) break the least code

A library-only change always fits (a) and (b). In general,
it's good for (c) too.

I propose the following change:

``Specialise'' make_pair for arrays in order to convert
them to pointers:

template <typename T1, typename T2, size_t S1, size_t S2>
pair<T1*, T2*> make_pair (T1 (&r1) [S1], T2 (&r2) [S2])
{
    return pair<T1*, T2*> (r1, r2);
}

template <typename T1, typename T2, size_t S1, size_t S2>
pair<const T1*, T2*> make_pair (const T1 (&r1) [S1], T2 (&r2) [S2])
{
    return pair<const T1*, T2*> (r1, r2);
}

template <typename T1, typename T2, size_t S1, size_t S2>
pair<T1*, const T2*> make_pair (T1 (&r1) [S1], const T2 (&r2) [S2])
{
    return pair<T1*, const T2*> (r1, r2);
}

template <typename T1, typename T2, size_t S1, size_t S2>
pair<const T1*, const T2*> make_pair (const T1 (&r1) [S1], const T2
(&r2) [S2])
{
    return pair<const T1*, const T2*> (r1, r2);
}

template <typename T1, typename T2, size_t S1>
pair<T1*, T2> make_pair (T1 (&r1) [S1], const T2& r2)
{
    return pair<T1*, T2> (r1, r2);
}

template <typename T1, typename T2, size_t S1>
pair<const T1*, T2> make_pair (const T1 (&r1) [S1], const T2& r2)
{
    return pair<const T1*, T2> (r1, r2);
}

template <typename T1, typename T2, size_t S2>
pair<T1, T2*> make_pair (const T1& r1, T2 (&r2) [S2])
{
    return pair<T1, T2*> (r1, r2);
}

template <typename T1, typename T2, size_t S2>
pair<T1, const T2*> make_pair (const T1& r1, const T2 (&r2) [S2])
{
    return pair<T1, const T2*> (r1, r2);
}

This works for make_pair ("a", 2), which has the
expected type pair<const char*, int>, as:

int a[2];
cout << typeid (make_pair (a, 3)).name ();

which prints pair<int*, int> as expected.

--

Valentin Bonnard


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Andrei Alexandrescu <andrewalex@hotmail.com>
Date: 1999/08/05
Raw View
In article <37A7EAB8.35E4@wanadoo.fr>,
  Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
[overloads for make_pair omitted]

Looks sensible. You may drop the const versions, as const will make
part of the template type. Please correct me if I'm wrong.

But, isn't it a case when you may need the actual fixed-size array?

Andrei



Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/08/05
Raw View
On 4 Aug 1999 15:25:28 GMT, Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:

>    make_pair ("a", 1)


> (4) innitialisation of an array member by the
>     construtor-argument-list isn't allowed

If we made array initialization legal, then we risk inefficiency:
   make_pair("Is C++ efficient",false);
creates a temporary char[18] to hold the string "Is C++ efficient".



>``Specialise'' make_pair for arrays in order to convert
>them to pointers:

This solution is also const nice.  I learned in the other thread
that the type of
   make_pair("Is C++ efficient",false);
is std::pair<char[18],bool>.  Note that the array of characters is
non-const.  But your solution deduces the type as
std::pair<const char *,bool>.


One possible problem is:  What if a future revision of C++ decides
to add array assignment and initialization?  In this future world,
we might want make_pair("ABC",true) to create a pair<char[4],bool>.


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/08/05
Raw View
Andrei Alexandrescu wrote:

> In article <37A7EAB8.35E4@wanadoo.fr>,
>   Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
> [overloads for make_pair omitted]
>
> Looks sensible.

Thank you.

> You may drop the const versions, as const will make
> part of the template type. Please correct me if I'm wrong.

Of course I didn't introduced const just to multiply the
number of overloaded functions by 3.

These templates functions should be choosen over the
existing one, which has the const.

> But, isn't it a case when you may need the actual fixed-size array?

Yes, and you may still create a pair yourself, w/o
the help of make_pair.

If make_pair handled 99% of pair<> creations, I would
be happy with that.

--

Valentin Bonnard


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/08/05
Raw View
In article <slrn7qhh1l.gc9.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>This solution is also const nice.  I learned in the other thread
>that the type of
>   make_pair("Is C++ efficient",false);
>is std::pair<char[18],bool>.  Note that the array of characters is
>non-const.  But your solution deduces the type as
>std::pair<const char *,bool>.



Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/08/06
Raw View
On 5 Aug 1999 18:28:20 GMT, Francis Glassborow

>(literals) for strings is already in use.  Wouldn't it be nice if we
>could say to the compiler, use your sense and make "string" be whatever
>type I clearly intend it to be so:

I think that compilers can already do this as an optimization.  For
example, consider this:
   const std::string s="hello world";
Literally this means:  At compile time, create a char[12] that holds the
chars 'hello world\0'.  At run time, create a std::string from this
array of characters.  This means copying 11 or 12 chars from the char[12]
array into the char* inside the std::string.  However, I think it is
entirely reasonable for the compiler to construct the std::string
directly at compile time.

How about non-const strings?
   std::string s="hello world";
I think here the compiler could create a const compiler generated string
   const std::string __s="hello world"; // compiler generated
Also, transform the original line to
   std::string s=__s;



>void fn(string);
>void gn(char *);
>
>int main() {
>
>fn("C++");      // passes a string by value
>gn("C");        // passes a pointer to a C style array of const char
>(and issues a warning before doing the conversion to a non-const array)

BTW, warning or error?  Anyway, I think that your ideas are already
possible, but as an optimization.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jaakko =?iso-8859-1?Q?J=E4rvi?= <jaakko.jarvi@cs.utu.fi>
Date: 1999/08/06
Raw View
Valentin Bonnard wrote:
>=20
> Andrei Alexandrescu wrote:
>=20
> > But, isn't it a case when you may need the actual fixed-size array?
>=20
> Yes, and you may still create a pair yourself, w/o
> the help of make_pair.
>=20
But can you?

The pair constructors are:

  pair() : first(T1()), second(T2()) {}
  pair(const T1& a, const T2& b) : first(a), second(b) {}

I can't see how a pair holding a fixed-size array could be constructed.
The first constructor involves casting to an array type, the second an
array assignment. AFAIK both are forbidden.

E.g. with Egcs1.1.2 -pedantic

  std::pair<int[1], int>();=20
 =20
    In method `pair<int[1],int>::pair<int[1], int>()':
    ANSI C++ forbids casting to an array type
    (see 5.2.3 (2) in the standard)

  int a[] =3D {1};
  std::pair<int[1], int>(a,1);

   In method `pair<int[1],int>::pair<int[1], int>(const int (&)[1],
const int &)':
   warning: ANSI C++ forbids assignment of arrays

/Jaakko
       ]
--=20
--- Jaakko J=E4rvi, jaakko.jarvi@cs.utu.fi
--- Turku Centre for Computer Science (www.tucs.fi)
--- Lemmink=E4isenkatu 14 A, FIN-20520 Turku, Finland
--- Phone: +358-2-333 8656, Fax: +358-2-333 8600
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/08/06
Raw View
In article <slrn7qjqla.52b.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>>void fn(string);
>>void gn(char *);
>>
>>int main() {
>>
>>fn("C++");      // passes a string by value
>>gn("C");        // passes a pointer to a C style array of const char
>>(and issues a warning before doing the conversion to a non-const array)
>
>BTW, warning or error?  Anyway, I think that your ideas are already
>possible, but as an optimization.

Warning as there is a special deprecated conversion from literal (char
const *) to char * to support legacy code.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/08/07
Raw View
Francis Glassborow wrote:
>
> In article <slrn7qhh1l.gc9.sbnaran@localhost.localdomain>, Siemel B.
> Naran <sbnaran@uiuc.edu> writes
> >This solution is also const nice.  I learned in the other thread
> >that the type of
> >   make_pair("Is C++ efficient",false);
> >is std::pair<char[18],bool>.  Note that the array of characters is
> >non-const.  But your solution deduces the type as
> >std::pair<const char *,bool>.
>
> From my perspective the problem is not really about arrays but about a
> very special kind of array, that of some kind of char which is used as a
> string in C.  In addition we allow a special way of writing values of
> this type by placing them inside double quotes.  However we also have an
> explicit string type (actually a potentially infinite set of string
> types) in C++.  However the most obvious way of writing values
> (literals) for strings is already in use.  Wouldn't it be nice if we
> could say to the compiler, use your sense and make "string" be whatever
> type I clearly intend it to be so:
>
> void fn(string);
> void gn(char *);
>
> int main() {
>
> fn("C++");      // passes a string by value
> gn("C");        // passes a pointer to a C style array of const char
> (and issues a warning before doing the conversion to a non-const array)
>
> If we could add a rule that C++ strings are preferred ... Oh well the
> idea is full of holes.

There could also be an additional syntax to allow directly
specifying that a string constant should be a std::string
constant. For example:

assert(typeid("Hello") == typeid(char const[6]));
assert(typeid("Hello"s) == typeid(std::string));


void foo(char const*);
void foo(std::string);

foo("Hello"); // calls foo(char const*)
foo("Hello"s); // calls foo(std::string)

"Hello"s would just be a shorthand for std::string("Hello"),
just as 1L is a shorthand for long(1).
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/08/07
Raw View
On 06 Aug 99 10:31:43 GMT, Jaakko J=E4rvi <jaakko.jarvi@cs.utu.fi> wrote:
>Valentin Bonnard wrote:

>> Yes, and you may still create a pair yourself, w/o
>> the help of make_pair.

>But can you?
>
>The pair constructors are:
>
>  pair() : first(T1()), second(T2()) {}
>  pair(const T1& a, const T2& b) : first(a), second(b) {}

First way:
   std::pair<char[4],bool> silly;
   strcpy(silly.first,"C++");
   silly.second=3Dtrue;

Second way:
   std::pair<std2::carray<char,4>,bool> silly(std2::carray<char,4>("C++")=
,true);
This second way fakes array assignment.  Maybe array assignment would be =
a
good idea.  Why was it left out of the language?

--=20
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Thomas Maeder <maeder@glue.ch>
Date: 1999/08/07
Raw View
Andrew Koenig schrieb:
>
>         template<typename T, int n> struct canon<T[n]> {
>                 typedef T* type;
>         };
>
>         template<typename T, int n> struct canon<const T[n]> {
>                 typedef const T* type;
>         };
>
>         // maybe we should do it for volatile and const volatile too

I don't see the point of having one specialization for each
cv-qualification possibility. Won't these qualifications make into T?

E.g.

canon<int[3]> -> T == int
canon<const int[3]> -> T == const int

etc.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]