12

Being not declared constexpr, std::forward will discard constexpr-ness for any function it forwards arguments to. Why is std::forward not declared constexpr itself so it can preserve constexpr-ness?

Example: (tested with g++ snapshot-2011-02-19)

#include <utility>

template <typename T> constexpr int f(T x) { return -13;}
template <typename T> constexpr int g(T&& x) { return f(std::forward<T>(x));}

int main() {
  constexpr int j = f(3.5f);
  // next line does not compile: 
  // error: ‘constexpr int g(T&&) [with T = float]’ is not a constexpr function
  constexpr int j2 = g(3.5f);
}

Note: technically, it would be easy to make std::forward constexpr, e.g., like so (note that in g std::forward has been replaced by fix::forward):

#include <utility>

namespace fix {
  /// constexpr variant of forward, adapted from <utility>:
  template<typename Tp>
  inline constexpr Tp&&
  forward(typename std::remove_reference<Tp>::type& t) 
  { return static_cast<Tp&&>(t); }

  template<typename Tp>
  inline constexpr Tp&&
  forward(typename std::remove_reference<Tp>::type&& t) 
  {
    static_assert(!std::is_lvalue_reference<Tp>::value, "template argument"
          " substituting Tp is an lvalue reference type");
    return static_cast<Tp&&>(t);
  }
} // namespace fix

template <typename T> constexpr int f(T x) { return -13;}
template <typename T> constexpr int g(T&& x) { return f(fix::forward<T>(x));}

int main() {
  constexpr int j = f(3.5f);
  // now compiles fine:
  constexpr int j2 = g(3.5f);
}

My question is: why is std::forward not defined like fix::forward ?

Note2: this question is somewhat related to my other question about constexpr std::tuple as std::forward not being constexpr is the technical reason why std::tuple cannot be created by calling its cstr with rvalues, but this question here obviously is (much) more general.

Community
  • 1
  • 1
Lars
  • 2,616
  • 3
  • 21
  • 18
  • 1
    quick note, identifiers beginning by `_[A-Z]` are reserved to the compiler implementers. Your program, as such, is ill-formed. – Matthieu M. Feb 24 '11 at 07:13
  • 4
    And _T is especially nasty if you should ever move to Windows, where it is a macro... – Bo Persson Feb 24 '11 at 18:55
  • 1
    @Matthieu M, @Bo Persson Thanks. I replaced all names _T by T etc. so others can try the code more safely / easily. – Lars Feb 24 '11 at 21:48

1 Answers1

10

The general answer is that the C++ committee's Library Working Group have not done an exhaustive trawl through the working draft looking for opportunities to use the new core facilities. These features have been used where people have had the time and inclination to look at possible uses, but there is not the time for exhaustive checking.

There are some papers regarding additional uses of constexpr in the works, such as those in the November 2010 mailing.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
  • Thanks. I knew the related document [N3231](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3231.html) already, but it does not mention section 20.3.3 on std::forward. -- What you provide is more a "social reason". I am interested in a "conceptual reason", i.e., is there anything wrong in making std::forward constexpr or would it be fine? – Lars Feb 23 '11 at 22:54
  • 4
    I can't see any reason why not at first glance. – Anthony Williams Feb 23 '11 at 22:57
  • With issue reports for making it possible to pass and call function pointers in constexpr functions (and literal function object types can be constexpr already), having std::forward be non-constexpr seems unfortunate. – Johannes Schaub - litb Feb 26 '11 at 06:16
  • 5
    [N3305](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3305.html) proposes to add constexpr for `std::forward` – Dave Abrahams Sep 12 '12 at 15:34