Boost logo

Boost :

From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2005-07-08 08:52:07


Paul Mensonides wrote:
>>-----Original Message-----
>>From: boost-bounces_at_[hidden]
>>[mailto:boost-bounces_at_[hidden]] On Behalf Of Tobias Schwinger
>

>>>That will remove any cv-qualifiers on a pointer to function
>>
>>(as in a
>>
>>>"const pointer to function"), but it won't remove the cv-qualifiers
>>>from a raw function type. There is no way to add or remove such
>>>qualifiers without taking the type apart and putting it
>>
>>back together with or without the cv-qualification.
>>
>>Is either way defined behaviour? Got some standard references
>>for me, perhaps?
>
>
> -----
> 8.3.5/4
>
> A cv-qualifier-seq shall only be part of the function type for a nonstatic
> member function, the function type to which a pointer to member refers, or the
> top-level function type of a function typedef declaration. The effect of a
> cv-qualifier-seq in a function declarator is not the same as adding
> cv-qualification on top of the function type, i.e., it does not create a
> cv-qualified function type. In fact, if at any time in the determination of a
> type a cv-qualified function type is formed, the program is ill-formed.
> -----

It is not too clear whether it applies to partial template specialization, since
we don't really "form" a type - we just consider a possibitity:

    typedef int my_const_function() const;

    template<typename T> struct remove_const { typedef T type; };
    template<typename T> struct remove_const< T const > { typedef T type; };

    // somwhere else
    remove_const<my_const_function>::type // ill-formed?

>
> There might be more references, but this gives a significantly strong
> implication that cv-qualification on function types is radically different than
> normal cv-qualification.

...and that cv-qualification on function types is intended for nonstatic member
functions only (at least that's the impression I get from reading that paragraph).

> The cv-qualifiers are modifying the implicit 'this'
> parameter. I.e. the cv-qualifiers don't modify the function type (all functions
> are 'const' because C++ doesn't treat functions as first-class objects); they
> modify an implicit formal parameter. So attempting to remove cv-qualification
> this way would be akin to transforming 'void (const int*)' into 'void (int*)'.
>

I don't find it very convincing -- we're talking about two different pairs of
shoes here (syntax and type system vs. semantic treatment), IMO.

>>>struct C { };
>>>
>>>template<class T> struct is_const_function
>>> : is_pointer_to_const_member_function<T C::*> { };
>>>

Another thought on this one: as you said already, before forming a type C::*T we
have to make sure it works for the T we have. But can we do it with T actually
being a type which renders our program ill-formed when encountered (and without
relying on undefined behaviour)?

<snip>
>>
>>In this particular case it doesn't cost much. But if I'm
>>going to do a trivial thing as finding out whether 'int' is a
>>(any cv-qualified) function I need a second non-trivial
>>template instantiation and a couple of trivial ones as you
>>mentioned already. I'm not sure this feature is worth its
>>price. Further, if your compiler is smart enough you can
>>easily write it yourself if you need it.
>
>
> Yes. On the same token, however, I can just as easily write any other sort of
> function type manipulation that I might need. The point is that a library like
> yours should prevent the need for me to do it.

Right. But is there a need for raw, cv-qualified functions in the first place?

> If the feature is not used, the
> only possible *significant* compile-time overhead that I see is preprocessing.

Right.

However, I'm not concerned about preprocessing at all (I use preprocessed files).
I also don't care about parsing time (it's comparatively little and it costs once
per translation unit). What counts is the complexitiy of using the metafunctions.

> This can be solved by making headers more granular (not a commentary on your
> library) and simply not including it. If it is used, then the user pays for it
> with a few template instantiations--just like anything else. From an
> implementation point-of-view (meaning the cost on your time personally),
> supporting this would be fairly easy if you don't try to make it work on
> compilers that are fundamentally broken in this area.
>

I don't find your suggestion of testing C::*T instead of T generally unattractive
(and ideally it might simplify things). The conditions for applying it would be:

(when integrating)
- be sure your suggestion builts on solid C++ (see above)
- find a nice name to disambiguate const and volatile property tags so I won't
   need an underscore suffix

(when the library is used)
- it works with the compiler
- the configuration allows it by specifying the same calling conventions for
   member and non member functions (and there is no MSVC __thiscall weirdness
   around)

>
>>>If that is the case, then you shouldn't be supporting open
>>
>>variadics.
>>
>>>Support for that adds significant overhead to the implementation.
>>>Granted, variadic function types are more common than cv-qualified
>>>function types, but they are still quite rare.
>>
>>Can't really say 'printf' is a dark corner of the language...
>
>
> The type of 'printf' may have C linkage which you can't do anything with on any
> conforming compiler. Basically, 'printf' is untouchable (in this context) in
> portable code.
>

Oh - I didn't mean 'printf' personally! It's just that the very first library
function a C programmer usually learns has a variadic argument list, so I found it
wrong to refer to open variadics as being an esoteric feature.

>
>>"Dark history", perhaps. And open variadics can be quite
>>useful. We shouldn't make assumptions on how many people use
>>them -- variadic functions have been there for a long time.
>
>
> Trust me, I'm a big fan of the concept of variadics. Given "reasonable"
> language support, they are a very enabling feature for a variety of things.
> (This is one of the reasons why I'm glad that C is still around. IMO, C++ tends
> to overlook the fundamental building blocks (e.g. procedural programming) as it
> grows. In some sense, C keeps C++ grounded. Of course, C is not the be all and
> end all of procedural programming. By now, we should have nested functions,
> with them comes closures, and with closures comes anonymous functions (i.e.
> lambda functions). These are fundamental building blocks.) Unfortunately, we
> don't yet have reasonable variadic support in C++. We need typesafe variadic
> functions, variadic templates, and variadic macros.

I agree.

> However right now, given
> that argument lists are an iterative syntactic structure (currently at odds with
> generic programming), that current variadic functions aren't typesafe (at odds
> with generic programming), and that you can't portably pass anything to them
> except POD's (at odds with generic programming)--it's a safe bet that function
> type manipulation (which would likely be done in generic code) of variadic
> function types will be extremely rare.

I have to annotate a tiny bit of rationale here: int func(int...) can be invoked
like func(1), so it should be a valid argument for a generic facility that accepts
a unary callable argument which in turn has an int parameter.

> Variadic functions (specifically, how to
> use them even to the point of how to invoke them) are way too semantically
> dependent on extra-linguistic knowledge like documentation. I certainly don't
> think you should remove support for them--I just see its utility as on par with
> cv-qualified function types--yet supporting it effectively doubles all of the
> template specializations required.

 From what I have benchmarked so far it seems that adding (partial)
specializations has a noticably smaller impact on the compilation time than adding
instantiations (as required for decision making and matching these specializations
twice).

> I don't buy the 'cost' argument as opposed to the 'completeness' argument, but
> I'm not terribly concerned over the lack of support. However, I'm a would-be
> user of a library, not the library author. If I was the library author,
> completeness would be a worthwhile goal in and of itself--it is a requirement
> for mastery of the subject. As a library author in other areas, the most
> annoying limitations are often those corner cases that you can do nothing about
> (and this isn't one of them), but present a barrior to completeness. It's the
> difference between "as good as can be given x, y, and z" and "ideal". My
> disagreement is more of a disagreement with perspective rather than over a
> particular feature.

Here is no disagreement at all (at least at this abstract level):

I'm all for completeness but I'm not convinced that what you are proposing is in
fact about completeness and not about emulating consistency where there is none.
Plus I'm wondering whether it's implementable in ISO C++ at all.

Thanks,

Tobias


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk