Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"static_cast<To>(from)" if and only if "To to{from}", or not?

Yesterday in the course of answering someone else's question I was surprised to discover that gcc 4.7.2 <type_traits> contained the trait template std::is_explicitly_convertible<From,To>, defined as the inverse of std::is_constructible_convertible<To,From>:

/// is_explicitly_convertible
template<typename _From, typename _To>
struct is_explicitly_convertible
: public is_constructible<_To, _From>
{ };

Searching for paper-trail, I then discovered that this trait ought not to have been there. A bug was raised against its inclusion in that version of the C++11 Standard Library and it was removed in gcc 4.8.0.

That bug report pointed out that std::is_explicitly_convertible (having been mandated in earlier drafts of the C++0x Standard), was removed from the draft Standard by N3047 in 2010.

N3047 explains this about-turn:

The remaining question is, in which way the also affected is_explicitly_convertible trait should be repaired. The basic choices are:

  1. Fix is_explicitly_convertible by returning to the current static_cast expression, no longer making is_explicitly_convertible dependent on is_constructible.
  2. Remove is_explicitly_convertible from the standard.

The first choice was considered, but it turned out that there exist quite different understandings of what "explicitly convertible" should actually mean. While some believe that static_cast correctly expresses this, others believed that the fixed is_constructible would provide a better meaning for is_explicitly_convertible as well. Therefore this paper recommends to remove the is_explicitly_convertible from the working draft. This should do no harm now, because nothing depends on that special definition yet. And if it turns out, that the trait would still be useful, it could be added in another revision of the standard.

This explanation seems to imply that the parties to the disagreement knew of cases in which, for an expression from of type From, static_cast<To>(from) would compile while To to{from}; would not; or vice versa.

Are there such cases?

If not, can anyone authoritatively (not speculatively, please) explain the distinction between static_castibility of From to To and constructibility of To from From that was in play here?

like image 414
Mike Kinghan Avatar asked Nov 03 '22 20:11

Mike Kinghan


1 Answers

First, some test code. TestA is your explicit construction, and TestB is your explicit static_casting:

template<typename To, typename From>
To TestA(From from) {
  To to{from};
  return to;
}
template<typename To, typename From>
To TestB(From from) {
  return static_cast<To>(from);
}

static_cast allows downcasting in an object heirarchy, while explicit construction does not:

struct Base {};
struct Derived:Base {};

int main() {
  Base* b;
  // TestA<Derived*>(b); -- fails to compile
  TestB<Derived*>(b);
}
like image 51
Yakk - Adam Nevraumont Avatar answered Nov 12 '22 18:11

Yakk - Adam Nevraumont