Skip to content

[libc++] Are some standard overloads of std::pow missing? #110241

Closed
@frederick-vs-ja

Description

@frederick-vs-ja

I'm referring to C++20/WG21 N4868 here, because the changes of additional overloads of std::pow introduced in C++23 by P1467R9 look defective and libc++ hasn't implemented P1467R9 yet.

In N4868 [complex.syn] there were 3 explicitly specified standard overloads of pow:

  template<class T> complex<T> pow  (const complex<T>&, const T&);
  template<class T> complex<T> pow  (const complex<T>&, const complex<T>&);
  template<class T> complex<T> pow  (const T&, const complex<T>&);

And then, several additional overloads were specified in N4868 [cmplx.over]/3, but their exact forms were not specified.

Currently, libc++ provides 4 overloads:

template <class _Tp>
inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> pow(const complex<_Tp>& __x, const complex<_Tp>& __y) {
return std::exp(__y * std::log(__x));
}
template <class _Tp, class _Up>
inline _LIBCPP_HIDE_FROM_ABI complex<typename __promote<_Tp, _Up>::type>
pow(const complex<_Tp>& __x, const complex<_Up>& __y) {
typedef complex<typename __promote<_Tp, _Up>::type> result_type;
return std::pow(result_type(__x), result_type(__y));
}
template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Up>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI complex<typename __promote<_Tp, _Up>::type> pow(const complex<_Tp>& __x, const _Up& __y) {
typedef complex<typename __promote<_Tp, _Up>::type> result_type;
return std::pow(result_type(__x), result_type(__y));
}
template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Tp>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI complex<typename __promote<_Tp, _Up>::type> pow(const _Tp& __x, const complex<_Up>& __y) {
typedef complex<typename __promote<_Tp, _Up>::type> result_type;
return std::pow(result_type(__x), result_type(__y));

If I understood correctly, only the first one is an explicitly specified overload, and the rest are additional overloads. So it seems that the remaining 2 overloads are missing.

However, when I attempted to added them during handling #110235, I found that it's very hard, if not impossible, to portably verify that these overloads are added. Because instantiating std::complex<NonFP> is unspecified and in some cases std::complex<std::complex<T>> would be instantiated when using braced-init-list due to the form of these overloads.
E.g. according to the current standard overload set, std::pow(std::complex<float>(1.0f), {1l, 1l}) would cause pow(const T&, const complex<T>&) (where T is complex<float>) to be detected, which in turn instantiates (probably nonsense) std::complex<std::complex<float>>.

It's not clear to me

  1. whether libc++ is effectively conforming now, i.e. lacking of these 2 overloads isn't observable in any conforming program, and
  2. whether there's any defect in the specification of explicitly overloads (effectively unchanged since C++20, see [complex.syn]) as they possibly cause std::complex<std::complex<T>> to be instantiated.

Edit: LWG3693 is somehow related.

Metadata

Metadata

Assignees

No one assigned

    Labels

    libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.questionA question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions