讓我們創建柯里化函式。
template <typename TFunc, typename TArg>
class CurryT
{
public:
CurryT(const TFunc &func, const TArg &arg)
: func(func), arg(arg )
{}
template <typename... TArgs>
decltype(auto) operator()(TArgs ...args) const
{ return func(arg, args...); }
private:
TFunc func;
TArg arg ;
};
template <typename TFunc, typename TArg>
CurryT<decay_t<TFunc>, remove_cv_t<TArg>>
Curry(const TFunc &func, const TArg &arg)
{ return {func, arg}; }
以及將函式解耦為單引數函式的函式:
// If single argument function (F(int)).
template <typename F>
static auto Decouple(const F &f, enable_if_t<is_invocable_v<F, int>> * = nullptr)
{
return f;
}
// If multiple arguments function (F(int, int, ...)).
template <typename F>
static auto Decouple(const F &f, enable_if_t<!is_invocable_v<F, int>> * = nullptr)
{
return [f](int v) { return Decouple( Curry(f, v) ); };
}
如果傳遞 2 個引數函式,一切正常:
auto f1 = Decouple(
[](int a, int b)
{ std::cout << a << " " << b << std::endl; }
);
f1(3)(4); // Outputs 3 4
但如果我添加更多引數
auto f2 = Decouple(
[](int a, int b, int c)
{ std::cout << a << " " << b << " " << c << std::endl; }
);
f(5)(6)(7);
編譯中斷:https ://coliru.stacked-crooked.com/a/10c6dba670d17ffa
main.cpp: In instantiation of 'decltype(auto) CurryT<TFunc, TArg>::operator()(TArgs ...) const [with TArgs = {int}; TFunc = main()::<lambda(int, int, int)>; TArg = int]':
main.cpp:17:26: error: no match for call to '(const main()::<lambda(int, int, int)>) (const int&, int&)'
17 | { return func(arg, args...); }
它打破了std::is_invocable.
由于除錯標準庫很困難,我創建了標準型別特征類的簡單版本:
template <typename F> true_type check(const F &, decltype( declval<F>()(1) )* );
template <typename F> false_type check(const F &, ...);
template <typename F>
struct invocable_with_int : decltype(check(declval<F>(), nullptr))
{};
template <typename F>
inline constexpr bool invocable_with_int_v = invocable_with_int<F>::value;
template<bool B>
struct my_enable_if {};
template<>
struct my_enable_if<true>
{ using type = void; };
template <bool B>
using my_enable_if_t = typename my_enable_if<B>::type;
問題仍然存在https://coliru.stacked-crooked.com/a/722a2041600799b0:
main.cpp:29:73: required by substitution of 'template<class F> std::true_type check(const F&, decltype (declval<F>()(1))*) [with F = CurryT<main()::<lambda(int, int, int)>, int>]'
它試圖解決對此函式的呼叫:
template <typename F> true_type check(const F &, decltype( declval<F>()(1) )* );
但是decltype (declval<F>()(1))*)失敗了。但是不應該因為模板替換失敗而將這個函式從多載決議中洗掉嗎?它在什么時候起作用Decouple第一次呼叫時起作用。但是當它第二次呼叫時,SFINAE 似乎被禁用,并且模板替換的第一次失敗給出了編譯錯誤。二級 SFINAE 是否有一些限制?為什么遞回呼叫模板函式不起作用?
該問題在 GCC 和 Clang 中重現。所以這不是編譯器錯誤。
uj5u.com熱心網友回復:
您的operator()多載是完全不受約束的,因此聲稱可以使用任何一組引數呼叫。只檢查宣告,而不是定義,以確定在多載決議中呼叫哪個函式。如果代入定義失敗,則 SFINAE 不適用。
因此,將您operator()的要求限制TFunc為可以使用TArg和TArgs...作為引數呼叫。
例如:
template <typename... TArgs>
auto operator()(TArgs ...args) const -> decltype(func(arg, args...))
uj5u.com熱心網友回復:
CurryT::operator()對我來說,您接受未知數量的引數很奇怪。
由于目標是有一個只接受一個引數的函式,我希望這個函式只接受一個引數。
CurryTIMO 取決于持有哪種函式CurryT::operator()應該回傳不同的型別:開始函式的回傳型別或其他版本的CurryT.
這是我使用std::bind_frontC 20 的方法:
namespace detail {
template <typename TFunc>
class CurryT
{
public:
explicit CurryT(TFunc f) : mF(std::move(f))
{}
template<typename T>
auto get(T&& x, int = 0) -> decltype(std::declval<TFunc>()(x)) {
return mF(x);
}
template<typename T>
auto get(T&& x, char) {
return CurryT<decltype(std::bind_front(mF, std::forward<T>(x)))>{
std::bind_front(mF, std::forward<T>(x))
};
}
template<typename T>
auto operator()(T&& x)
{
return this->get(std::forward<T>(x), 1);
}
private:
TFunc mF;
};
}
template<typename F>
auto Decouple(F&& f)
{
return detail::CurryT<std::decay_t<F>>{std::forward<F>(f)};
}
https://godbolt.org/z/eW9r4Y6Ea
請注意,這種方法整數引數不像您的解決方案那樣被強制。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/471400.html
上一篇:無法從url查詢陣列引數
