让我们创建竞逐函数。
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两人身上。所以它不是编译器的错误。
发布于 2022-05-09 14:36:04
您的operator()重载是完全不受约束的,因此声称可以使用任何参数集调用。只检查声明,而不是定义,以确定在重载解析中调用哪个函数。如果定义中的替换失败,则不适用SFINAE。
因此,约束您的operator()要求TFunc可以用TArg和TArgs...作为参数进行调用。
例如:
template <typename... TArgs>
auto operator()(TArgs ...args) const -> decltype(func(arg, args...))发布于 2022-05-09 15:12:26
对我来说,奇怪的是,您的CurryT::operator()接受未知数量的参数。
由于目的是要有一个只接受一个论点的函数,所以我期望这个函数只接受一个论点。
海事组织根据CurryT持有的函数类型,CurryT::operator()应该返回不同的类型:返回启动函数的类型或其他版本的CurryT。
下面是我使用来自std::bind_front的C++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://stackoverflow.com/questions/72173127
复制相似问题