Re: Type traits and accessibility
On 23 Apr., 01:22, Nikolay Ivchenkov <ts...@mail.ru> wrote:
On 22 Apr, 17:09, Daniel Krugler <daniel.krueg...@googlemail.com>
wrote:
On 19 Apr., 20:59, Nikolay Ivchenkov <ts...@mail.ru> wrote:
We can conclude that this program is ill-formed considering two facts
(but not only one of them):
1) the constructor Y(int) is used (so, it shall be defined), and
2) the definition of the constructor Y(int) is not provided.
These facts collectively can be expressed as "undefined function is
used".
This example doesn't matter in this discussion, because it does
not properly reflect the definition of std::is_constructible.
If you look at the definition of std::is_constructible, it obviously
does not describe a complete program, so we cannot argue
about possibly missing definitions of any potentially used
entity of this definition, because that cannot be deduced from
the definition.
The problem is that the same I could say, for example, about
"std::is_constructible<int &>::value": it is stated that if the
reference is value-initialized then the entire program is ill-formed,
but the expression T(), where T is "lvalue reference to int", could
still be considered as well-formed unless otherwise specified
somewhere else.
This discussions starts to cycle a bit. I tried to point out that
the definition of is_constructible refers to the ill-formed state
from a program that can be deduced from this partially defined
program. I also tried to make clear that any completing program
may contain constructs that would - in combination with this
partial program - still cause an ill-formed program, among
these reasons are that the completed program may omit
the definition of a used entity. These other defects are unrelated
to the definition of is_constructible - in particular unrelated
to the reference of an ill-formed expression within this partial
program. IMO the current wording is clear and unambiguous in
this regard.
Referring to your example of "std::is_constructible<int &>::value"
I do not see this problem, because the given
typedef int& T;
the construction
T()
does cause the program to be instantaneously ill-formed (note
that this assertion is unaffected by the point in term when such
an ill-formed program would produce the required diagnostic).
This situation cannot be compared with
struct X { X(int); };
applied to the construction
static_cast<X>(create<int>())
because the expression itself is potentially well-formed.
The fact that the program could be *potentially* ill-formed
if any definition of a used entity - like that of the
constructor X::X(int) or that of the specialization
int&& create<int>() - is missing can only be deduced from
a completed program. This means it is meaningless to
debate about the meaning of "ill-formed" within the
definition of is_constructible/is_convertible in regard
to these aspects.
In other words: Any *additional* programming errors contained
in a program using std::is_constructible (like any missing
definition of a used entity)
What is the "additional programming error"? For example:
#include <typeinfo>
class X;
int main()
{
typeid(X);
}
May the missing definition of X be considered as "additional
programming error"?
I don't understand this example in combination with
the discussion of the definition of is_constructible.
It does not mimic the definition of is_constructible
and no use of is_constructible is in sight. If we would
try to bring this into the came, as in
#include <typeinfo>
#include <type_traits>
class X;
int main()
{
bool b = std::is_constructible<int&>::value;
typeid(X);
}
would still not help us. Neither does the ill-formed
program construction (created by the expression
typeid(X)) influence the definition of is_constructible,
nor does the definition of is_constructible make
this program well-formed. Concluding, I don't see
how this example points out a defect in the
definition of the compiler support trait.
Similarly, the following program
#include <typeinfo>
class X;
int main()
{
typeid(X);
}
is ill-formed because:
1) the class type X is used as the operand of the typeid operator
(i.e. in the context where it is required to be completely-defined),
and
2) the definition of the class X is not provided prior to the typeid
expression.
Is the expression typeid(X) well-formed?
It is clearly ill-formed
It is not obvious.
According to [expr.typeid]/3:
"[..] If the type of the expression is a class type, the class
shall be completely-defined. [..]"
which is a requirement to the implementation to diagnose
a violation, see also [intro.compliance]/1+2.
but that does not affect in any case
the situation with is_constructible and is_convertible.
Are you sure?
#include <iostream>
#include <type_traits>
#include <typeinfo>
class X;
struct Y
{
template <class T>
Y(T &, std::type_info const & = typeid(T));
};
int main()
{
std::cout << std::is_constructible<Y, X &>::value;
}
Well, this is a good example that highlights a potential problem
in both support traits, but it is not related to typeid or to a
missing definition of a type. I construct a different example that
better shows the potential problem I see and does not depend
on missing definitions of entities:
struct X {
X() = delete;
};
struct Y {
template <class T> Y(T &, T const & = T());
};
int main() {
bool b = std::is_constructible<Y, X&>::value; // OK?
};
As of current language rules this is a non-SFINAE ill-formed
situation, because the defect does not occur in the "immediate
context of a function type and its template parameter types"
([temp.deduct]/8). Examples like this could also require
speculative compilation and this is a requirement that is
extremely hard to realize (E.g. it would also mean that some
instantiation error within some remote class template has to be
caught).
I agree that the current definition of both is_constructible
and is_convertible requires a compiler to handle them
without making the program ill-formed and this is probably
not realistic to implement for these cases. We may want to
restrict here to "the immediate context" as [temp.deduct]/8
does.
I am talking about the inverse consequence: we can't strictly conclude
that an expession is ill-formed when the specification asserts ill-
formedness of the entire program only.
I don't see how this affects the definition of is_constructible,
as shown above.
Directly. If in some particular case the ill-formedness of the
expression CE is unspecified then the respective value of
std::is_constructible<TYPES>::value is also unspecified.
I don't see the situation you tried to show above as a situation
of an unspecified ill-formedness. The usage of typeid(X) is clearly
ill-formed, similarly as that of sizeof(X) for an undefined entity X.
If you think that this is not clear from the standard, this is a
different issue, I believe.
If you think that the behavior of the GNU C++ compiler is
wrong, how can you prove it?
This is a compiler defect, because it violates 14.9.2 [temp.deduct].
It is nude matter.
I don't know what this is supposed to mean. But the ambiguity
situation
you were referring to is clearly a normal SFINAE situation, because
char (*)[sizeof static_cast<T>(create<D *>()) is part of the template
parameter type and also within the "immediate context".
Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]