C++ 如何正确处理此SFINAE?

C++ 如何正确处理此SFINAE?,c++,c++11,sfinae,C++,C++11,Sfinae,我遇到了一个基于参数包特性启用/禁用重载的问题。这是我试图回答的另一个问题。我有一个静态的go()函数,如果所有的mixin类型都有一个静态的check()方法,那么应该调用该函数。同样,如果mixin包没有check()方法,则应该调用另一个静态go()方法。我尝试创建基于此策略启用的重载,但由于某种原因,当我调用它时,它会选择第二个重载,该重载尝试调用handle(): 模板 使用first=T; 模板 结构检查器 { 公众: 模板 静态void go() { 自动x{(Mixins::ch

我遇到了一个基于参数包特性启用/禁用重载的问题。这是我试图回答的另一个问题。我有一个静态的
go()
函数,如果所有的
mixin
类型都有一个静态的
check()
方法,那么应该调用该函数。同样,如果
mixin
包没有
check()
方法,则应该调用另一个静态
go()
方法。我尝试创建基于此策略启用的重载,但由于某种原因,当我调用它时,它会选择第二个重载,该重载尝试调用
handle()

模板
使用first=T;
模板
结构检查器
{
公众:
模板
静态void go()
{
自动x{(Mixins::check(),0)…};
(无效)x;
}
静态void go()
{
自动x{(Mixins::handle(),0)…};
(无效)x;
}
};

struct A{static void check(){std::cout您无法区分这两种类型的
go
。当这两种类型都可行时,重载解析将首选非模板
go

将正确地消除
foo
的重载。但是,此处的错误不是替换失败,因为未命名函数模板参数的默认值不取决于函数模板的参数。通常,当您在类型
t
上参数化了类,并且希望约束成员函数时
f
基于
T
的某些属性,您可以使用
T
的别名强制该依赖关系:

template <class T>
struct foo {
  template <class U=T,
            class=typename std::enable_if<std::is_integral<U>::value>::type>
  void f();
};
模板
结构foo{
模板
无效f();
};
但是,在OP的情况下,同样的技巧不起作用,因为OP的类是在包上参数化的,并且无法为参数包提供默认值。我们必须更巧妙:

template<class T = void,
         class = first<T, typename std::enable_if<has_check<Mixins>::value, T>::type...>>
static void foo(int)
{
    auto x{ (Mixins::check(), 0)... };
    (void)x;
}
模板
静态void foo(int)
{
自动x{(Mixins::check(),0)…};
(无效)x;
}

首先强制
enable_if
扩展对SFINAE有效。

我试图使用类似的东西,但我想我在实现时犯了一些错误。无论如何,我感谢你的帮助。我会使用它。:)非常好!谢谢你的帮助!:)无关:不知道你是否在乎,但你会得到帮助当
Mixins
为空时,
auto x{…}
行上的编译器错误。
auto x{};
格式不正确。通常的解决方法是在初始值设定项中添加一个额外的前导0:
auto x{0,(Mixins::check(),0);
@Casey感谢您指出这一点。下面的
0
也很重要吗?是的。带括号的初始值设定项列表是展开参数包的一个方便地方,可以保证按顺序计算。这段代码使用我称之为“初始值设定项列表技巧”来计算任意包扩展表达式-在本例中为
Mixins::check()
和/或
Mixins::handle()
-将其用作构造带括号的init整数列表的副作用。每次出现
(Mixins::check(),0)
在展开式中计算一个
check
函数,然后使用逗号运算符丢弃结果,并在初始值设定项列表中粘贴一个
0
。完成后,您计算了所有
check
函数,最终得到一个语法上有效的初始值设定项,它只有一个名称,因此我们可以尝试告诉编译器不要警告我们它未使用,方法是将它强制转换为
void
(void)x
,或者更方便地将它传递给忽略它的lambda:
[](std::initializer_list){}(x);
@Casey。我试过修复它,但没用。你能看到出了什么问题吗?如果我们不能解决,我会再发一个问题。:)
template<class =
         first<void,
               typename std::enable_if<has_check<Mixins>::value>::type...>>
template <class T>
struct foo {
  template <class U=T,
            class=typename std::enable_if<std::is_integral<U>::value>::type>
  void f();
};
template<class T = void,
         class = first<T, typename std::enable_if<has_check<Mixins>::value, T>::type...>>
static void foo(int)
{
    auto x{ (Mixins::check(), 0)... };
    (void)x;
}