Как я могу использовать std::lcm
с std::ranges::fold_left
с C++23 GCC 13.2.0/, что, возможно, лучше?
#include <algorithm>
#include <initializer_list>
#include <numeric>
int main() {
unsigned int a = std::ranges::fold_left(std::initializer_list<unsigned int>{3U, 5U}, 2U, std::lcm<unsigned int>);
return 0;
}
Приведенный выше код не работает в GCC 13.2.0 и в cppinsights.io, который, очевидно, использует один и тот же компилятор, с тем же результатом:
/home/insights/insights.cpp:6:22: error: no matching function for call to object of type 'const __fold_left_fn'
6 | unsigned int a = std::ranges::fold_left(std::initializer_list<unsigned int>{3U, 5U}, 2U, std::lcm<unsigned int>);
| ^~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/ranges_algo.h:3821:7: note: candidate template ignored: couldn't infer template argument '_Fp'
3821 | operator()(_Range&& __r, _Tp __init, _Fp __f) const
| ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/ranges_algo.h:3812:7: note: candidate function template not viable: requires 4 arguments, but 3 were provided
3812 | operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Error while processing /home/insights/insights.cpp.
Проверив пример на cppreference.com , я сравнил подпись std::plus и std::multiplies с std::lcm и обнаружил (более или менее) следующее:
template< class M, class N >
constexpr std::common_type_t<M, N> lcm( M m, N n );
template< class T = void >
struct plus {
constexpr T operator()( const T& lhs, const T& rhs ) const {
return lhs + rhs;
}
};
template< class T = void >
struct multiplies {
constexpr T operator()( const T& lhs, const T& rhs ) const {
return lhs * rhs;
}
};
Это наверняка объясняет проблему.
Каков рекомендуемый/"стандартный" способ?
Действительно ли идея заключается в том, что я сам реализую структуру?
И почему интерфейсы такие противоречивые?
Учитывая функцию с сигнатурой template< class M, class N > constexpr std::common_type_t<M, N> lcm( M m, N n );
, lcm<unsigned int>
будет недостаточно, чтобы выделить одну перегрузку.
Вам придется предоставить оба аргумента шаблона (lcm<unsigned int, unsigned int>
) или устранить неоднозначность другим способом, например static_cast<unsigned int(*)(unsigned int, unsigned int)>(lcm)
.
Однако std::lcm<unsigned, unsigned>
не является адресуемой функцией. Это означает, что вам не разрешено передавать его адрес другой функции.
Рекомендуемый способ — создать собственную структуру. Это легко сделать с помощью лямбды:
unsigned a = std::ranges::fold_left(std::initializer_list<unsigned>{3U, 5U}, 2U, [](unsigned m, unsigned n) {
return std::lcm(m, n);
});
std::lcm<unsigned int>
->std::lcm<unsigned int, unsigned int>