Boost logo

Boost :

Subject: [boost] Remembering that T(a) can cause dangerous conversion like a C-style cast
From: Kazutoshi Satoda (k_satoda_at_[hidden])
Date: 2011-11-03 08:03:42


An essential question:
Should boost::lambda::constructor<int>()("") compiles?

It does compile with Boost 1.47.0 . But I think it shouldn't.

I have crafted a general replacement of T(a) as a workaround for
dangerous conversions caused by T(a) which may happen in some kinds of
templates.
      http://ideone.com/iZE1Z
      unary_initialized<T>(a).value
And I thought of that the above workaround (or something similar) may be
suitable to be provided within boost::initialized .

Now I want to share the idea and to hear interests or evaluations in the
community about such extension and underlying issues, before starting
further acts.

Here is the background story:
A while ago, I had a conversation about dangerous conversion that can be
caused by the following expression with variadic templates in C++11.
      T(std::forward<Args>(args)...)
This expression is meant to obtain a prvalue of type T which is direct
initialized from any given argument list. But if a single argument was
given, this becomes T(std::forward<Arg>(arg)) and further, for example,
may become int("") and compiles as reinterpret_cast which is likely
unexpected. Here is a relevant quote from the standard 5.2.3 p1:
> ... If the expression list is a single expression, the type conversion
> expression is equivalent (in definedness, and if defined in meaning) to
> the corresponding cast expression (5.4). ...
(Note: 5.2.3 describes the behavior of T(a), and 5.4 describes the
behavior of (T)a.)
To avoid the unexpected conversion, I first proposed use of T{...} .
But it is not a perfect solution because it changes the meaning in some
cases like std::vector<int> . After that, I crafted a tricky workaround.
      http://ideone.com/FLoDk
      pack_initialized<T>(std::forward<Args>(args)...).value

The above story was about C++11. But it revealed that similar dangerous
conversion can be also formed in C++98, C++03 as T(a) in some kinds of
templates.

Searching in the boost directory (trunk r75213), I found some
occurrences of the problem:
      boost/lambda/construct.hpp:37:
      http://www.boost.org/doc/libs/1_47_0/boost/lambda/construct.hpp
        return T(a1);
      boost/xpressive/regex_actions.hpp:632:
      http://www.boost.org/doc/libs/1_47_0/boost/xpressive/regex_actions.hpp
        return T(a0);
As shown in the top of this message, I picked boost::lambda::constructor
as a concrete example, and verified that the problem really exists in
the wild.

Thinking more, I wonder why such dangerous conversion was explicitly
injected to T(a) in the first place. I first thought of some
C-compatibility issues. But now I think it cannot be, because T(a) is a
new construct in C++. Is it possible to remove this dangerous
conversion path in a future revision of the standard?

Perhaps I should go to comp.std.c++ about the last question.

-- 
k_satoda

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