sfinae在递归功能中没有工作
让我们创建咖喱函数。
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/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;
问题保持相同:
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) )* );
但是 exptype(Declval&lt; f&gt; f&gt;()(1))*)
失败。但是,由于模板替代失败,是否应该从超负荷分辨率中删除此功能?当 decouple
首次调用时,它起作用。但是,当被称为第二次时,Sfinae似乎被禁用,模板替换的第一个失败会产生汇编误差。次级Sfinae是否有某种限制?为什么递归调用模板函数不起作用?
该问题在GCC和Clang中复制。因此,它不是编译器错误。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的
operator()
Overload完全不受约束,因此声称与任何一组参数都可以调用。仅检查声明而不是定义,以确定在过载分辨率中呼叫的功能。如果替换为定义,则不适用Sfinae。因此,将您的
operator()
限制为tfunc
,用targ
和targs ...
作为参数可调用。例如:
Your
operator()
overload is completely unconstrained and therefore claims to be callable with any set of arguments. Only declarations, not definitions, are inspected to determine which function to call in overload resolution. If substitution into the definition then fails, SFINAE does not apply.So, constrain your
operator()
to requireTFunc
to be callable withTArg
andTArgs...
as arguments.For example:
对我来说,奇怪的是,您的
curryt :: operator()
接受未知数的参数。由于目的是具有一个仅接受一个参数的函数,所以我期望此功能只接受一个参数。
IMO取决于哪种函数
curryt
保持curryt :: operator()
应返回其他类型:返回启动功能的类型或其他版本的curryt
。这是我使用
std :: bind_front
的方法,来自C ++ 20:https:// https:// godbolt.org/z/ew9r4y6ea
用这种方法注明整数论点并不像您的解决方案中那样强制。
For me it is strange that your
CurryT::operator()
accepts unknown number of arguments.Since aim is to have a functions which accept only one argument I expected that this function will accept only one argument.
IMO depending what kind of function
CurryT
holdsCurryT::operator()
should return a different type: return type of starting function or another version ofCurryT
.Here is my approach using
std::bind_front
from C++20:https://godbolt.org/z/eW9r4Y6Ea
Note with this approach integer argument is not forced like in your solution.