Topic: ConceptGCC Alpha 5 , std::Integral concept definition incorrect


Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Wed, 14 Mar 2007 13:06:40 CST
Raw View
On Mar 12, 9:12 pm, "kwikius" <a...@servocomm.freeserve.co.uk> wrote:
> On 12 Mar, 21:40, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
>
> > I'm not sure what "T doesn't stand for one type within a particular
> > signature" means.
>
> Going back to the std::Integral concept definition of operator +
>
> concept Integral <typename T> {
> T operator +(T,T);
>
> };
>
> In the addition  int() + long()  , I don't see which particular model
> is the compiler to prefer, int or long. Therefore I assumed that T can
> stand for any model or combination in the above signature, else I dont
> see how it can work or how the compiler can match the signature.

You will always have a placeholder for 'T' when you use Integral. In
your case above, T will either be int (and we'll use int + int) or it
will be long (and we'll use long + long). Example:

  template<typename T>
  requires Integral<T>
  T do_add(T x, T y) {
    return x + y;
  }

Which + does do_add use? Integral<T>::operator+

When happens when we instantiate do_add<int>? Integral<T> is
instantiated to Integral<int>, and the operator+ we get in the
instantiation is

  int Integral<int>::operator+(int, int)

which uses the built-in int + int.

  Cheers,
  Doug

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kwikius" <andy@servocomm.freeserve.co.uk>
Date: Thu, 15 Mar 2007 09:50:39 CST
Raw View
On 14 Mar, 19:06, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
> On Mar 12, 9:12 pm, "kwikius" <a...@servocomm.freeserve.co.uk> wrote:

> > On 12 Mar, 21:40, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
>
> > > I'm not sure what "T doesn't stand for one type within a particular
> > > signature" means.
>
> > Going back to the std::Integral concept definition of operator +
>
> > concept Integral <typename T> {
> > T operator +(T,T);
>
> > };
>
> > In the addition  int() + long()  , I don't see which particular model
> > is the compiler to prefer, int or long. Therefore I assumed that T can
> > stand for any model or combination in the above signature, else I dont
> > see how it can work or how the compiler can match the signature.
>
> You will always have a placeholder for 'T' when you use Integral. In
> your case above, T will either be int (and we'll use int + int) or it
> will be long (and we'll use long + long). Example:
>
>   template<typename T>
>   requires Integral<T>
>   T do_add(T x, T y) {
>     return x + y;
>   }
>
> Which + does do_add use? Integral<T>::operator+

hmm That is a no brainer, there is nothing to solve, but represents
AFAICS a significant narrowing of my example.

Suppose I would write the function as follows:

 template<Integral TL, Integral TR>

  std::Addable<TL,TR>::result_type
  do_add(TL x, TR y)
  {
    return x + y;
  }

int main()
{
  do_add(1,1L);
}

My guess is that we then get an error message telling us that:

 the addition is not defined for std::Integral<int> or
std::Integral<long>

candidates are...

 std::Integral<int>::operator +(int,int)
 std::Integral<long>::operator +(long,long)

etc. Anything else would violate the Integral concept as written
AFAICS.

Here for instance is a non concept version which exhibits a similar
property...

template <typename TL>
TL do_add(TL const & lhs , TL const & rhs)
{
   return TL();
};


int main()
{
   do_add(1,1L);
}

FWIW Its a variant of the following issue AFAICS, which doesnt
consider the full depth of operations on fundamental types
adequately.
#include <complex>

int main()
{
   std::complex<double> x;
   x + 1.f;
}

Maybe I'm missing something though...

regards
Andy Little




---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kwikius" <andy@servocomm.freeserve.co.uk>
Date: Fri, 9 Mar 2007 09:02:27 CST
Raw View
std::Integral<T> concept in conceptGCC  4.1.1-alpha 5 <concepts> looks
incorrect to me:

char + char is AFAIK an int not a char:

in <concepts>

concept Integral<typename T> {
.
T operator+(T, T); // doesnt work for char among others


}

 or int + long etc...

#include <concepts>

template <typename TL, typename TR>
where std::Integral<TL> && std::Integral<TR>
std::Addable<TL,TR>::result_type
std_add (TL const & lhs,TR const & rhs)
{
   return lhs + rhs; // line 10
}

/* output:

D:\projects\concepts>make
conceptg++ -IC:/quan/quan-trunk -IC:/quanta/quanta-trunk -IC:/boost/
include/boos
t-1_33_1 -c test.cpp
test.cpp: In function 'std::Addable<T, U>::result_type std_add(const
TL&, const
TR&)':
test.cpp:10: error: no match for 'operator+' in 'lhs + rhs'
/opt/conceptgcc-4.1.1-alpha-5/lib/gcc/i686-pc-cygwin/4.1.1/../../../../
include/c
++/4.1.1/bits/concepts.h:193: note: candidates are: T
std::Integral<T>::operator
+(const T&, const T&)
/opt/conceptgcc-4.1.1-alpha-5/lib/gcc/i686-pc-cygwin/4.1.1/../../../../
include/c
++/4.1.1/bits/concepts.h:192: note:  T std::Integral<T>::operator+
(const T&)
/opt/conceptgcc-4.1.1-alpha-5/lib/gcc/i686-pc-cygwin/4.1.1/../../../../
include/c
++/4.1.1/bits/concepts.h:192: note:  TR std::Integral<TR>::operator+
(const TR&)
/opt/conceptgcc-4.1.1-alpha-5/lib/gcc/i686-pc-cygwin/4.1.1/../../../../
include/c
++/4.1.1/bits/concepts.h:193: note:  TR std::Integral<TR>::operator+
(const TR&,
const TR&)

*/

regards
Andy Little

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Fri, 9 Mar 2007 11:17:52 CST
Raw View
On Mar 9, 10:02 am, "kwikius" <a...@servocomm.freeserve.co.uk> wrote:
> std::Integral<T> concept in conceptGCC  4.1.1-alpha 5 <concepts> looks
> incorrect to me:
>
> char + char is AFAIK an int not a char:

Right, it's an int, although that can be implicitly converted back
into a char (thus, Integral<char> does type-check).

> in <concepts>
>
> concept Integral<typename T> {
> .
> T operator+(T, T); // doesnt work for char among others
>
> }
>
>  or int + long etc...

We've discussed this once or twice, and there is an interesting design
choice to be made. Should we model the entire promotion system, with
all of its requisite messiness? Or does it make more sense to keep the
concept definitions more pure, so that constrained templates that use
the concepts can also work with user-defined Integral types that can't
just insert themselves into the type-promotion system, because they
rely on user-defined conversions.

> #include <concepts>
>
> template <typename TL, typename TR>
> where std::Integral<TL> && std::Integral<TR>
> std::Addable<TL,TR>::result_type
> std_add (TL const & lhs,TR const & rhs)
> {
>    return lhs + rhs; // line 10
>
> }
[snip ConceptGCC error]

You will need to add the std::Addable<TL,TR> requirement to the where
clause, to say that you can add a TL to a TR. There is a ConceptGCC
bug here... it should have added the std::Addable<TL, TR> requirement
after seeing its use in the return type of std_add.

  Cheers,
  Doug

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kwikius" <andy@servocomm.freeserve.co.uk>
Date: Mon, 12 Mar 2007 12:06:32 CST
Raw View
On 9 Mar, 17:17, "Douglas Gregor" <doug.gre...@gmail.com> wrote:

(Note to the moderators. This is basically a copy of another post I
sent earlier today BST which seems to have disappeared)


> We've discussed this once or twice, and there is an interesting design
> choice to be made. Should we model the entire promotion system, with
> all of its requisite messiness?

To be a model of concept X the result of these operations should type
check correctly shouldnt they?

If concepts cant handle messiness they wont be much use IMO.

> Or does it make more sense to keep the
> concept definitions more pure, so that constrained templates that use
> the concepts can also work with user-defined Integral types that can't
> just insert themselves into the type-promotion system, because they
> rely on user-defined conversions.

A signature such as

template <TR>
where Integral<Addable<TL,TR>::result_type>
Addable<TL,TR>::result_type operator+(TL, TR);

seems to work for both inbuit integral types and UDT's.

I'm not sure where the implicit conversions requirement enters the
picture? Is this just for Integral or any Concept parameter?


>From what you are saying the T parameter in the concept definition is
meant to mean 'any model of T" within a particular signature.

 Two different models of T must by nature have some differences, even
though they model the same concept. It would appear to me that if you
cant distinguish them it won't be possible to exploit those
differences in a particular signature in the Concept definition, e.g
by means of where clauses. IOW you have lost a lot of expressiveness
by T not standing in for one type within the signature. Also the
concept definition itself is pretty loose so allowing the possibility
of unintended combinations to slip through.  Finally the self
documentation properties are not as good.

Consider trying to model the concept of a physical quantity as
modelled in my quan library.
(Incidentally matrices have similar issues I think, IOW the
result_type hence signature is dependent on the particular models
input. )

Assume some Concept Quantity, and some models length and time.

length and time are both models of Quantity. length is addable with
length as they are dimensionally equivalent but length is not addable
with time as they are not dimensionally equivalent.

Similarly in division. If two quantities are the same dimensionally
the result is numeric, else its a quantity. These things define what
the Quantity type is, which AFAICS is the purpose of Concepts...

I would hope to be able to express these things within the concept
definition. (These are currently done using  SFINAE)
(I hope the intent of other traits and concepts below is clear)

auto concept Quantity<typename T>{

    typename Value_type;
    where IsNumeric<value_type>;

    template <Quantity Rhs>
    where DimensionallyEquivalent<T,Rhs>
    && Quantity<Addable<T,Rhs>::result_type>
    Addable<T,Rhs>::result_type operator + ( T, Rhs);

    template <Quantity Rhs>
    where DimensionallyEquivalent<T,Rhs>
    && Quantity<Subtractable<T,Rhs>::result_type>
    Subtractable<T,Rhs>::result_type operator - ( T, Rhs);

    template <Quantity Rhs>
    where DimensionallyEquivalent<T,RHS>
    && IsNumeric< Divisible<T,Rhs>::result_type>
    Divisible<T,Rhs>::result_type operator / (T, Rhs);

    template <Quantity Rhs>
    where ! DimensionallyEquivalent<T,RHS>
    && Quantity< Divisible<T,Rhs>::result_type>
    Divisible<T,Rhs>::result_type operator / (T, Rhs);

    template <Quantity Rhs>
    where DimensionallyEquivalent <T, reciprocal<Rhs>::type>
    && IsNumeric<Multiplicable<T,Rhs>::result_type>
    Multiplicable<T,Rhs>::result_type
    operator * ( T, Rhs);

    template <Quantity Rhs>
    where !DimensionallyEquivalent <T, reciprocal<Rhs>::type>
    && Quantity<Multiplicable<T,Rhs>::result_type>
    Multiplicable<T,Rhs>::result_type
    operator * ( T, Rhs);

    template <Numeric Rhs>
    && SameType<T, Multiplicable<T,Rhs>::result_type>
    Multiplicable<T,Rhs>::result_type
    operator * ( T, Rhs);

    .... etc

}


 (If I cant do something like the above then a quantity will look
exactly like a float) but the above does not seem to be possible if T
doesnt stand for one type within a particular signature.

regards
Andy Little










---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Mon, 12 Mar 2007 15:40:30 CST
Raw View
On Mar 12, 2:06 pm, "kwikius" <a...@servocomm.freeserve.co.uk> wrote:
> On 9 Mar, 17:17, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
> > We've discussed this once or twice, and there is an interesting design
> > choice to be made. Should we model the entire promotion system, with
> > all of its requisite messiness?
>
> To be a model of concept X the result of these operations should type
> check correctly shouldnt they?

Yes, and char + char can be implicitly converted into a char.

> If concepts cant handle messiness they wont be much use IMO.

They can. We need to determine if they should, in the concepts that we
put into the Standard Library for everyone to use.

> A signature such as
>
> template <TR>
> where Integral<Addable<TL,TR>::result_type>
> Addable<TL,TR>::result_type operator+(TL, TR);
>
> seems to work for both inbuit integral types and UDT's.%A
Yes.

> I'm not sure where the implicit conversions requirement enters the
> picture? Is this just for Integral or any Concept parameter?

Any concept parameter. We permit implicit conversions when matching
concept operations, because requiring exact signature matches would
break a huge amount of existing code.

> >From what you are saying the T parameter in the concept definition is
>
> meant to mean 'any model of T" within a particular signature.
>
>  Two different models of T must by nature have some differences, even
> though they model the same concept.

Sure.

> It would appear to me that if you
> cant distinguish them it won't be possible to exploit those
> differences in a particular signature in the Concept definition, e.g
> by means of where clauses. IOW you have lost a lot of expressiveness
> by T not standing in for one type within the signature.

You can distinguish them, if you want. But to handle the general case,
one needs to look only at their common properties; concepts let you
describe those common properties.

> Also the
> concept definition itself is pretty loose so allowing the possibility
> of unintended combinations to slip through.

If the concept definition weren't loose, 95% of existing code thatthat
uses the STL would break the second we turned concepts on.
That said, I can't say that I've seen any believable cases where
concepts are too loose.

> Finally the self
> documentation properties are not as good.

I don't understand what this means.

> I would hope to be able to express these things within the concept
> definition. (These are currently done using  SFINAE)
> (I hope the intent of other traits and concepts below is clear)
>
> auto concept Quantity<typename T>{
>
>     typename Value_type;
>     where IsNumeric<value_type>;
>
>     template <Quantity Rhs>
>     where DimensionallyEquivalent<T,Rhs>
>     && Quantity<Addable<T,Rhs>::result_type>
>     Addable<T,Rhs>::result_type operator + ( T, Rhs);
>
[snip]
>
>     .... etc
>
> }
>
>  (If I cant do something like the above then a quantity will look
> exactly like a float) but the above does not seem to be possible if T
> doesnt stand for one type within a particular signature.

The above code looks perfectly fine to me. Alas, you won't be able to
try it with ConceptGCC, because we don't have support for member
signatures yet.

I'm not sure what "T doesn't stand for one type within a particular
signature" means. Whenever you use Quantity<T>, T is some specific
type. It may vary from instantiation to instantiation (that's what
template parameters do!), but within one instantiation it always
refers to the same type. Without that constant, we would not be able
to type-check templates reliably.

  Cheers,
  Doug

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kwikius" <andy@servocomm.freeserve.co.uk>
Date: Mon, 12 Mar 2007 19:12:25 CST
Raw View
On 12 Mar, 21:40, "Douglas Gregor" <doug.gre...@gmail.com> wrote:

> I'm not sure what "T doesn't stand for one type within a particular
> signature" means.

Going back to the std::Integral concept definition of operator +

concept Integral <typename T> {
T operator +(T,T);
};

In the addition  int() + long()  , I don't see which particular model
is the compiler to prefer, int or long. Therefore I assumed that T can
stand for any model or combination in the above signature, else I dont
see how it can work or how the compiler can match the signature.

Note that :

concept Integral <typename T> {

template <typename TR>
Addable<T,TR>::result_type operator +(T,TR);
};

doesnt suffer from this ambiguity.

regards
Andy Little











---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]