Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #6082 > unrolled thread
| Started by | Marcel Müller <news.5.maazl@spamgourmet.org> |
|---|---|
| First post | 2011-06-02 14:33 +0200 |
| Last post | 2011-06-02 10:40 -1000 |
| Articles | 6 — 3 participants |
Back to article view | Back to comp.lang.c++
Casting template argument Marcel Müller <news.5.maazl@spamgourmet.org> - 2011-06-02 14:33 +0200
Re: Casting template argument Victor Bazarov <v.bazarov@comcast.invalid> - 2011-06-02 10:17 -0400
Re: Casting template argument Marcel Müller <news.5.maazl@spamgourmet.org> - 2011-06-02 22:10 +0200
Re: Casting template argument Pete Becker <pete@versatilecoding.com> - 2011-06-02 10:21 -1000
Re: Casting template argument Marcel Müller <news.5.maazl@spamgourmet.org> - 2011-06-02 22:34 +0200
Re: Casting template argument Pete Becker <pete@versatilecoding.com> - 2011-06-02 10:40 -1000
| From | Marcel Müller <news.5.maazl@spamgourmet.org> |
|---|---|
| Date | 2011-06-02 14:33 +0200 |
| Subject | Casting template argument |
| Message-ID | <4de78326$0$6554$9b4e6d93@newsspool4.arcor-online.net> |
I want to cast a template argument. Unfortunately gcc creates an error
as if the cast has never been there. Is this not allowed generally?
-----
#include <string.h>
// Sorted vector of T with the key type K using the comparer C.
template <class T, class K, int (*C)(const T* e, const K* k)>
class sorted_vector
{public:
// Find an element by it's key.
// The function will return NULL if no such element is in the container.
T* find(const K* key) const;
// Ensure an element with a particular key.
// This will either return a reference to a pointer to an existing object
// which equals to key or a reference to a NULL pointer which is
// created at the location in the container where a new object with key
// should be inserted.
T*& get(const K* key);
// Erase the element which equals key and return the removed pointer.
// If no such element exists the function returns NULL.
T* erase(const K* key);
};
// data structure, POD
struct data
{ char Key[10];
char Value[10];
};
// Works
int (*const comparer)(const data*, const char*)
= (int (*)(const data*, const char*))&strcmp;
// does not work, see below
typedef sorted_vector<data, char,
(int (*)(const data*, const char*))&strcmp> stringmap;
-----
test6.cpp:34: error: could not convert template argument `strcmp' to `int
(*)(const data*, const char*)'
Of cource, strcmp does not compare against objects of type data, but
since data is a POD type the equivalence of const data* and const char*
should not raise serious problems, and a helper function should be
superfluous.
Marcel
[toc] | [next] | [standalone]
| From | Victor Bazarov <v.bazarov@comcast.invalid> |
|---|---|
| Date | 2011-06-02 10:17 -0400 |
| Message-ID | <is8629$ook$1@dont-email.me> |
| In reply to | #6082 |
On 6/2/2011 8:33 AM, Marcel Müller wrote:
> I want to cast a template argument. Unfortunately gcc creates an error
> as if the cast has never been there. Is this not allowed generally?
Yep. Not allowed.
The requirement is that a non-type template argument is expected to be
the address of a function, "expressed as & id-expression where the & is
optional if the name refers to a function or array". That means that
the "explicit type conversion expressions" are *not allowed*. Bummer.
What you perhaps need is to supply your pointer expression (by just
using the name of the function) and hope that the compiler performs the
necessary conversion itself. Standard, [temp.arg.nontype]/5 explains
what conversions are applied:
<<
The following conversions are performed on each expression used as a
non-type template-argument. If a non-type template-argument cannot be
converted to the type of the corresponding template-parameter then
the program is ill-formed.
— for a non-type template-parameter of integral or enumeration type,
integral promotions (4.5) and integral conversions (4.7) are applied.
— for a non-type template-parameter of type pointer to object,
qualification conversions (4.4) and the array-to-pointer conversion
(4.2) are applied. [Note: In particular, neither the null pointer
conversion (4.10) nor the derived-to-base conversion (4.10) are applied.
Although 0 is a valid template-argument for a non-type
template-parameter of integral type, it is not a valid template-argument
for a non-type template-parameter of pointer type. ]
— For a non-type template-parameter of type reference to object, no
conversions apply. The type referred to by the reference may be more
cv-qualified than the (otherwise identical) type of the
templateargument. The template-parameter is bound directly to the
template-argument, which must be an lvalue.
— For a non-type template-parameter of type pointer to function, only
the function-to-pointer conversion (4.3) is applied. If the
template-argument represents a set of overloaded functions (or a pointer
to such), the matching function is selected from the set (13.4).
— For a non-type template-parameter of type reference to function, no
conversions apply. If the template-argument represents a set of
overloaded functions, the matching function is selected from the
set (13.4).
— For a non-type template-parameter of type pointer to member function,
no conversions apply. If the template-argument represents a set of
overloaded member functions, the matching member function is
selected from the set (13.4).
— For a non-type template-parameter of type pointer to data member,
qualification conversions (4.4) are applied.>>
Your case seems to fall into the fourth bullet point. What you will
likely to encounter is another compiler error since the function is not
of the type expected by the compiler. You need a wrapper function.
> -----
> #include <string.h>
>
> // Sorted vector of T with the key type K using the comparer C.
> template <class T, class K, int (*C)(const T* e, const K* k)>
> class sorted_vector
> {public:
> // Find an element by it's key.
> // The function will return NULL if no such element is in the container.
> T* find(const K* key) const;
> // Ensure an element with a particular key.
> // This will either return a reference to a pointer to an existing object
> // which equals to key or a reference to a NULL pointer which is
> // created at the location in the container where a new object with key
> // should be inserted.
> T*& get(const K* key);
> // Erase the element which equals key and return the removed pointer.
> // If no such element exists the function returns NULL.
> T* erase(const K* key);
> };
>
> // data structure, POD
> struct data
> { char Key[10];
> char Value[10];
> };
>
> // Works
> int (*const comparer)(const data*, const char*)
> = (int (*)(const data*, const char*))&strcmp;
"Works" - what do you mean? You have a C-style cast here. Whether it
achieves what you expect is not known until you actually try invoking
that function using that 'comparer' pointer.
> // does not work, see below
> typedef sorted_vector<data, char,
> (int (*)(const data*, const char*))&strcmp> stringmap;
Have you tried without the cast? What do you get?
> -----
>
> test6.cpp:34: error: could not convert template argument `strcmp' to `int
> (*)(const data*, const char*)'
>
>
> Of cource, strcmp does not compare against objects of type data, but
> since data is a POD type the equivalence of const data* and const char*
> should not raise serious problems, and a helper function should be
> superfluous.
<shrug> You're trying to cheat the system by using the C-style cast.
That's *usually* an invitation for UB.
V
--
I do not respond to top-posted replies, please don't ask
[toc] | [prev] | [next] | [standalone]
| From | Marcel Müller <news.5.maazl@spamgourmet.org> |
|---|---|
| Date | 2011-06-02 22:10 +0200 |
| Message-ID | <4de7ee37$0$7626$9b4e6d93@newsspool1.arcor-online.net> |
| In reply to | #6083 |
On 02.06.11 16.17, Victor Bazarov wrote: > On 6/2/2011 8:33 AM, Marcel Müller wrote: >> I want to cast a template argument. Unfortunately gcc creates an error >> as if the cast has never been there. Is this not allowed generally? > > Yep. Not allowed. [...] > Your case seems to fall into the fourth bullet point. What you will > likely to encounter is another compiler error since the function is not > of the type expected by the compiler. You need a wrapper function. What a pity. Unfortunately I need a dozen wrappers, because I have different data types that differ only in the value type. This can be easily coded by a template function but it is not that pretty. >> // Works >> int (*const comparer)(const data*, const char*) >> = (int (*)(const data*, const char*))&strcmp; > > "Works" - what do you mean? You have a C-style cast here. Whether it > achieves what you expect is not known until you actually try invoking > that function using that 'comparer' pointer. Following the Rules of POD types, the pointer to the structure and to the first structure element should be the same. And as far as the strings are null terminated i see no problem. In fact I showed not the excerpt of my code, but a reduced one for demonstration purpose only. The real implementation of sorted_vector<> internally works only with void* to prevent code size explosions. The function is cast to int (*)(const void*, const void*). The core worker knows nothing about the real data type. sorted_vector is a type safe wrapper. This has been working for many years. >> // does not work, see below >> typedef sorted_vector<data, char, >> (int (*)(const data*, const char*))&strcmp> stringmap; > > Have you tried without the cast? What do you get? Exactly the same message. In this case I did not expect anything else. >> Of cource, strcmp does not compare against objects of type data, but >> since data is a POD type the equivalence of const data* and const char* >> should not raise serious problems, and a helper function should be >> superfluous. > > <shrug> You're trying to cheat the system by using the C-style cast. > That's *usually* an invitation for UB. Well, the application is platform dependent for other, functional reasons anyway. The reinterpret cast from const data* to const char* is AFAIK no UB. But this does not automatically apply to casting the function pointer to a function with another argument type. On my target platform it makes no difference. All pointers arguments except for member function pointers are treated in the same way. So what is UB in general is not necessarily UB on this specific platform. Marcel
[toc] | [prev] | [next] | [standalone]
| From | Pete Becker <pete@versatilecoding.com> |
|---|---|
| Date | 2011-06-02 10:21 -1000 |
| Message-ID | <2011060210211182589-pete@versatilecodingcom> |
| In reply to | #6091 |
On 2011-06-02 10:10:30 -1000, Marcel Müller said: > > Well, the application is platform dependent for other, functional > reasons anyway. The reinterpret cast from const data* to const char* is > AFAIK no UB. But this does not automatically apply to casting the > function pointer to a function with another argument type. On my target > platform it makes no difference. All pointers arguments except for > member function pointers are treated in the same way. So what is UB in > general is not necessarily UB on this specific platform. > Undefined behavior arises from valid code constructs for which the C++ language definition does not impose any requirements. That doesn't depend in any way on the compiler that you're using or on the target platform. The *consequences* of using code whose behavior is undefined depend on the compiler and the platform. -- Pete Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The Standard C++ Library Extensions: a Tutorial and Reference (www.petebecker.com/tr1book)
[toc] | [prev] | [next] | [standalone]
| From | Marcel Müller <news.5.maazl@spamgourmet.org> |
|---|---|
| Date | 2011-06-02 22:34 +0200 |
| Message-ID | <4de7f3f0$0$7624$9b4e6d93@newsspool1.arcor-online.net> |
| In reply to | #6093 |
On 02.06.11 22.21, Pete Becker wrote: >> So what is >> UB in general is not necessarily UB on this specific platform. > > Undefined behavior arises from valid code constructs for which the C++ > language definition does not impose any requirements. That doesn't > depend in any way on the compiler that you're using or on the target > platform. This is UB with respect to the C++ language. The documentation of a specific compiler may define the behavior in cases where the C++ language does not. Passing pointer arguments is exactly defined on my platform. So the result of my cast is defined behavior, by all means with the three compilers that are supported (IBM, gnu, Watcom). > The *consequences* of using code whose behavior is undefined depend on > the compiler and the platform. Some code behavior is even undefined if you exactly know the platform and the compiler. E.g. accessing objects after they have been deleted. Marcel
[toc] | [prev] | [next] | [standalone]
| From | Pete Becker <pete@versatilecoding.com> |
|---|---|
| Date | 2011-06-02 10:40 -1000 |
| Message-ID | <2011060210404116688-pete@versatilecodingcom> |
| In reply to | #6097 |
On 2011-06-02 10:34:55 -1000, Marcel Müller said: > On 02.06.11 22.21, Pete Becker wrote: >>> So what is >>> UB in general is not necessarily UB on this specific platform. >> >> Undefined behavior arises from valid code constructs for which the C++ >> language definition does not impose any requirements. That doesn't >> depend in any way on the compiler that you're using or on the target >> platform. > > This is UB with respect to the C++ language. The documentation of a > specific compiler may define the behavior in cases where the C++ > language does not. > Passing pointer arguments is exactly defined on my platform. So the > result of my cast is defined behavior, by all means with the three > compilers that are supported (IBM, gnu, Watcom). Thus utterly missing the point. Again: the C++ langauge definition does not tell you what happens when you do this, so the behavior is undefined. > >> The *consequences* of using code whose behavior is undefined depend on >> the compiler and the platform. > > Some code behavior is even undefined if you exactly know the platform > and the compiler. E.g. accessing objects after they have been deleted. > Code whose behavior is undefined has undefined behavior *even if* you exactly know the platform and the compiler, and *even if* the compiler defines what happens. Undefined behavior is about what the C++ standard requires, not about what a particular compiler does or doesn't do. In particular, undefined behavior is not a synonym for "something bad will probably happen". -- Pete Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The Standard C++ Library Extensions: a Tutorial and Reference (www.petebecker.com/tr1book)
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web