Topic: C++0x, SFINAE, decltype: ill-formed or just a deduction failure?
Author: SG <s.gesemann@gmail.com>
Date: Fri, 16 Oct 2009 09:34:58 CST Raw View
On 8 Sep., 20:46, Doug Gregor <doug.gre...@gmail.com> wrote:
> On Sep 7, 1:21 am, SG <s.gesem...@gmail.com> wrote:
> > My goal here is to see whether it's possible to test whether an
> > arbitrary expression that successfully parses is actually valid or not
> > via SFINAE+decltype.
>
> You can test arbitrary expressions, but there are two major
> limitations to (extended)SFINAE:
>
> 1) Access control still happens after template argument deduction,
> so you will get a hard error if your expression makes use of an
> inaccessible member.
>
> 2) If type-checking the expression causes the instantiation of any
> class templates (or partial specializations thereof), any errors
> within those instantiations will be hard errors.
Thanks again, Doug, for your insights. I think we can do something
about (1).
According to Daniel Kr gler, std::is_convertible already requires
compiler magic to implement because of its definition (including
access control). The ability to check expressions for "well-
formedness" including access control is obviously desirable. If it was
possible to implement these traits in vanilla C++0x it would also
allow users to come up with their own, possibly more advanced traits
and concepts emulations which I think is very desirable.
You're saying "access control still happens after template argument
deduction" but that doesn't rule out a modified or extended decltype
primitive. In the context of argument deduction, decltype could be
restricted to public functions. Alternativly, there could be a
"pdecltype" where the initial p stands for public and is restricted to
public functions.
Such a decltype variant would allow users to come up with their own
advanced traits system that includes access checking and would also
make std::is_convertible implementable without further compiler-magic,
as far as I can tell.
Opinions?
Cheers,
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Mon, 7 Sep 2009 02:21:50 CST Raw View
I'm testing G++ 4.4.1 with respect to SFINAE and would like some
clarification on what is ill-formed and what is just considered a
decuction failure (SFINAE) in the following examples.
All the test programs are of the form
template<typename T> T&& make();
XXX
template<typename T, typename = decltype( YYY )>
int test(int) { return 1; }
template<typename T>
int test(...) { return 0; }
int main() { return test<Type>(0); }
where I replaced XXX and YYY with different declarations, definitions,
and expressions.
Case 1:
XXX: typedef int Type;
void foo(int*);
YYY: foo(make<T>())
Compiles fine with G++ 4.4.1.
Return code: 0 (as expected, no int&& -> int* conversion)
Case 2:
XXX: typedef int Type;
void foo(int&);
YYY: foo(make<T>())
Compiles fine with G++ 4.4.1.
Return code: 0 (as expected, no int&& -> int& conversion)
Case 3:
XXX: typedef int Type;
//void foo(int&);
YYY: foo(make<T>())
Does NOT compile with G++ 4.4.1:
"foo has not been declared"
Case 4:
XXX: typedef int Type;
void foo(int) = delete;
YYY: foo(make<T>())
Does NOT compile with G++ 4.4.1:
"deleted function void foo(int) used"
Case 4:
XXX: struct Type {
Type(Type const&) = delete;
Type(Type &&);
};
void foo(Type);
YYY: foo(make<T>())
Compiles fine with G++ 4.4.1.
Return code: 1 (as expected, Type is move-constructible)
Case 4:
XXX: struct Type {
Type(Type const&) = delete;
Type(Type &&);
};
void foo(Type);
YYY: foo(make<T&>()) // <-- lvalue argument
Does NOT compile with G++ 4.4.1:
"deleted function Type::Type(const Type&) used"
As you can see some errors are fatal. Is this behaviour expected or is
it due to a compiler bug?
My goal here is to see whether it's possible to test whether an
arbitrary expression that successfully parses is actually valid or not
via SFINAE + decltype.
Thanks in advance,
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Mathias Gaunard <loufoque@gmail.com>
Date: Tue, 8 Sep 2009 00:53:02 CST Raw View
On 7 sep, 10:21, SG <s.gesem...@gmail.com> wrote:
> Case 3:
> XXX: typedef int Type;
> //void foo(int&);
> YYY: foo(make<T>())
>
> Does NOT compile with G++ 4.4.1:
> "foo has not been declared"
That appears normal.
The compiler needs to know whether foo is a function, function object
or a type to give sense to that expression.
So you need to provide at least one declaration of foo; the arity or
the types of the arguments should be of no importance however.
> Case 4:
> XXX: typedef int Type;
> void foo(int) = delete;
> YYY: foo(make<T>())
>
> Does NOT compile with G++ 4.4.1:
> "deleted function void foo(int) used"
> Case 4 [actually, 5]:
> XXX: struct Type {
> Type(Type const&) = delete;
> Type(Type &&);
> };
> void foo(Type);
> YYY: foo(make<T&>()) // <-- lvalue argument
>
> Does NOT compile with G++ 4.4.1:
> "deleted function Type::Type(const Type&) used"
I don't know about these, but I suspect deleted functions are taken
into account later, after template argument substitution.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Doug Gregor <doug.gregor@gmail.com>
Date: Tue, 8 Sep 2009 12:46:23 CST Raw View
On Sep 7, 1:21 am, SG <s.gesem...@gmail.com> wrote:
> All the test programs are of the form
>
> template<typename T> T&& make();
>
> XXX
>
> template<typename T, typename = decltype( YYY )>
> int test(int) { return 1; }
>
> template<typename T>
> int test(...) { return 0; }
>
> int main() { return test<Type>(0); }
>
> where I replaced XXX and YYY with different declarations, definitions,
> and expressions.
> Case 3:
> XXX: typedef int Type;
> //void foo(int&);
> YYY: foo(make<T>())
>
> Does NOT compile with G++ 4.4.1:
> "foo has not been declared"
That's a bug. "foo" is a dependent name, so when name lookup fails to
find any "foo" at template argument deduction time it's a SFINAE
error.
> Case 4:
> XXX: typedef int Type;
> void foo(int) = delete;
> YYY: foo(make<T>())
>
> Does NOT compile with G++ 4.4.1:
> "deleted function void foo(int) used"
Definitely a bug in GCC. Use of a deleted function is meant to be a
SFINAE error.
> Case 4:
> XXX: struct Type {
> Type(Type const&) = delete;
> Type(Type &&);
> };
> void foo(Type);
> YYY: foo(make<T&>()) // <-- lvalue argument
>
> Does NOT compile with G++ 4.4.1:
> "deleted function Type::Type(const Type&) used"
Also a bug in GCC, for the same reason as in the other Case 4.
> My goal here is to see whether it's possible to test whether an
> arbitrary expression that successfully parses is actually valid or not
> via SFINAE + decltype.
You can test arbitrary expressions, but there are two major
limitations to (extended) SFINAE:
1) Access control still happens after template argument deduction,
so you will get a hard error if your expression makes use of an
inaccessible member.
2) If type-checking the expression causes the instantiation of any
class templates (or partial specializations thereof), any errors
within those instantiations will be hard errors.
- Doug
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Tue, 8 Sep 2009 12:47:41 CST Raw View
On 8 Sep., 08:53, Mathias Gaunard <loufo...@gmail.com> wrote:
> On 7 sep, 10:21, SG <s.gesem...@gmail.com> wrote:
>
> > Case 3:
> > XXX: typedef int Type;
> > //void foo(int&);
> > YYY: foo(make<T>())
>
> > Does NOT compile with G++ 4.4.1:
> > "foo has not been declared"
>
> That appears normal.
> The compiler needs to know whether foo is a function, function object
> or a type to give sense to that expression.
It does not need to know about it *before* instantiation. Some
function "foo" may be found via ADL while attempting to instantiate
the template. Since T is part of that expression, lookup of "foo" is
delayed and failure to find something at instantiation-time should in
my opinion result in a deduction failure instead of a fatal error. The
above example doesn't differ much from the following one
XXX: struct Type {};
YYY: make<T>() + make<T>()
which compiles fine using G++4.4.1 and the program returns 0. It
compiles even though the compiler didn't see any "operator+"
declaration. It compiles because it's considered a deduction failure.
In case the current draft deems these cases to be fatal errors
consider the posts of mine a plea for reconsideration. With "concepts"
removed we could at least get "syntactical expression constraints" via
SFINAE+decltype.
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Mathias Gaunard <loufoque@gmail.com>
Date: Wed, 9 Sep 2009 16:51:21 CST Raw View
On 8 sep, 20:47, SG <s.gesem...@gmail.com> wrote:
> The
> above example doesn't differ much from the following one
>
> XXX: struct Type {};
> YYY: make<T>() + make<T>()
That differs a lot. This is parsable without semantic information. The
former is not.
Whether foo(make<T>()) is a constructor call or an operator() cannot
be deduced without a definition of foo.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Thu, 10 Sep 2009 11:40:21 CST Raw View
On 10 Sep., 00:51, Mathias Gaunard <loufo...@gmail.com> wrote:
> On 8 sep, 20:47, SG <s.gesem...@gmail.com> wrote:
>
> > The
> > above example doesn't differ much from the following one
>
> > XXX: struct Type {};
> > YYY: make<T>() + make<T>()
>
> That differs a lot.
I disagree on the "a lot" part.
> This is parsable without semantic information. The
> former is not.
Have you tried? The following program "parses" and compiles without
problems:
template<typename T> T&& make();
template<typename T, typename = decltype( foo(make<T>()) )>
void bar(int) {}
As Doug explained, foo is a dependent name and as such lookup is
delayed. It doesn't matter what exactly it refers to. It's not
interpreted as a typeid, though, because it's not preceeded by the
typename keyword. That's all disambiguation we need. Some function
"foo" may *follow* this template definition that may be found via ADL,
for example. With respect to namelook up it's not different from
template<typename T>
void baz(T const& t) {
foo(t); // foo is again a dependent name
}
which, of course, also "parses" without any preceeding declaration of
"foo".
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Doug Gregor <doug.gregor@gmail.com>
Date: Fri, 11 Sep 2009 13:58:35 CST Raw View
On Sep 10, 10:40 am, SG <s.gesem...@gmail.com> wrote:
> On 10 Sep., 00:51, Mathias Gaunard <loufo...@gmail.com> wrote:
>
> > On 8 sep, 20:47, SG <s.gesem...@gmail.com> wrote:
>
> > > The
> > > above example doesn't differ much from the following one
>
> > > XXX: struct Type {};
> > > YYY: make<T>() + make<T>()
>
> > That differs a lot.
>
> I disagree on the "a lot" part.
>
> > This is parsable without semantic information. The
> > former is not.
>
> Have you tried? The following program "parses" and compiles without
> problems:
>
> template<typename T> T&& make();
>
> template<typename T, typename = decltype( foo(make<T>()) )>
> void bar(int) {}
>
> As Doug explained, foo is a dependent name and as such lookup is
> delayed.
Right. For reference, dependent names are covered in section 14.6.2
[temp.dep] of the C++ standard. Paragraph 1 covers the case under
discussion.
- Doug
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]