reference_wrapper<T> and incomplete types

83 views
Skip to first unread message

Fernando Pelliccioni

unread,
Dec 12, 2012, 3:25:45 PM12/12/12
to std-dis...@isocpp.org
Hi all,

Is the following code valid ?

struct A;

struct B
{
    B(A& a) : a_(a) {}
    std::reference_wrapper<A> a_;
};

struct A
{
};

According to the Standard, for reference_wrapper<T>, Is it allowed that T be an incomplete type?
From what I see, it is not explicitly stated in the Standard. On the contrary, for shared_ptr<T> is explicitly stated.

Does the Standard allows references to incomplete types?
Is the following code valid ?

struct A;

struct B
{
    B(A& a) : a_(a) {}
    A& a_;
};

struct A
{
};

Do you consider it right to allow that T to be incomplete for reference_wrapper<T> ?

Thanks and Regards,
Fernando Pelliccioni.

Daniel Krügler

unread,
Dec 12, 2012, 3:47:07 PM12/12/12
to std-dis...@isocpp.org
2012/12/12 Fernando Pelliccioni <fpelli...@gmail.com>:
> Hi all,
>
> Is the following code valid ?

I don't think so.

> struct A;
>
> struct B
> {
> B(A& a) : a_(a) {}
> std::reference_wrapper<A> a_;
> };
>
> struct A
> {
> };
>
> According to the Standard, for reference_wrapper<T>, Is it allowed that T be
> an incomplete type?

No. std::reference_wrapper does not have an explicit statement for
this, therefore
the general rule [res.on.functions] p2:

"In particular, the effects are undefined in the following cases:
[..]
— if an incomplete type (3.9) is used as a template argument when
instantiating a template component,
unless specifically allowed for that component."

applies.

> From what I see, it is not explicitly stated in the Standard. On the
> contrary, for shared_ptr<T> is explicitly stated.

Yes, this is intended here (also for unique_ptr for non-arrays, btw.).

> Does the Standard allows references to incomplete types?

Sure.

> Is the following code valid ?
>
> struct A;
>
> struct B
> {
> B(A& a) : a_(a) {}
> A& a_;
> };
>
> struct A
> {
> };

This is valid, yes.

> Do you consider it right to allow that T to be incomplete for
> reference_wrapper<T> ?

For most parts of the type specification an incomplete type could work.
Of-course you would need to add extra wording in regard to the instantiation of
the operator() overload.

One more serious problem (because it effects the whole template
instantiation and not a single member) are the implications of
[refwrap] p3 b3:

"The template instantiation reference_wrapper<T> shall define a nested
type named argument_type as a
synonym for T1 only if the type T is any of the following:
[..]
— a class type with a member type argument_type; the type T1 is
T::argument_type."

Assume that the previous two bullets (T is a function type or pointer
thereof or a pointer to member) do not apply. Now if T is incomplete,
the type described here cannot be determined. It might exist or might
not. So, when T is incomplete the member type does not exist. But when
T is completed, a following instantiation would give a
reference_wrapper that has such a type. This is a clear violation of
the ODR and thus UB.

The same problem arises via the weak result type described in p2 and
the potential member types first_argument_type and
second_argument_type described in p4.

- Daniel

Daniel Krügler

unread,
Dec 12, 2012, 4:07:14 PM12/12/12
to std-dis...@isocpp.org
2012/12/12 Daniel Krügler <daniel....@gmail.com>:
For completeness I should add one further - albeit presumably exotic - situation
that can cause problems with incomplete object types here. This is when T would
actually be a type that overrides the unary operator& (The "address-of
operator").

Remember that it the internals of reference_wrapper are unspecified
but constraints
are imposed to ensure that it is copyable and assignable. This makes
it probable that
it uses operator& or something equivalent (hopefully it uses
std::address but this seems
not required) to determine the address because it stores a plain
pointer. This again
means that it would be unclear which actual reference you will get
when attempting to
access it via one of the member/free functions.

> - Daniel

Fernando Pelliccioni

unread,
Dec 12, 2012, 4:25:19 PM12/12/12
to std-dis...@isocpp.org

--



Daniel, thank you very much for your explanation.
I didn't consider all these implications.
I thought that std::reference_wrapper was as simple as the boost::reference_wrapper.
Conclusion, not replace boost::reference_wrapper by std::reference_wrapper.
Reply all
Reply to author
Forward
0 new messages