我在根据参数包的特征启用/禁用重载时遇到了问题。这是我试图回答的另一个问题。我有一个静态的 go()
函数,如果所有的 Mixins
类型都有一个静态的 check()
方法,它应该被调用。同样,如果 Mixins
包 没有 有一个 check( )
方法。我尝试创建基于此策略启用的重载,但出于某种原因,当我调用它时,它选择了尝试调用 handle()
的 second 重载:
template<class T, class...>
using first = T;
template<class... Mixins>
struct Checker
{
public:
template<class =
first<void,
typename std::enable_if<has_check<Mixins>::value>::type...>>
static void go()
{
auto x{ (Mixins::check(), 0)... };
(void)x;
}
static void go()
{
auto x{ (Mixins::handle(), 0)... };
(void)x;
}
};
struct A { static void check() { std::cout << "check() "; } };
struct B { static void check() { std::cout << "check() "; } };
int main()
{
Checker<A, B>::go();
}
我收到一条错误消息,提示 A
没有名为 handle()
的成员。这一直困扰着我,但我找不到解决方法。如何解决此问题?如何根据参数包正确协调重载决议?
最佳答案
你没有什么可以区分go
的两种味道的.重载解析将优先选择非模板 go
当两者都可行时。 The ...
vs. int
technique works :
template<class... Mixins>
struct Checker
{
private:
template<class =
first<void,
typename std::enable_if<has_check<Mixins>::value>::type...>>
static void foo(int)
{
auto x{ (Mixins::check(), 0)... };
(void)x;
}
static void foo(...)
{
auto x{ (Mixins::handle(), 0)... };
(void)x;
}
public:
static void go() {
foo(0);
}
};
由于 foo
的两个重载可以调用foo(0)
,但是foo(int)
是比 foo(...)
更好的匹配这样当它没有被 SFINAE 淘汰时,重载解析会更喜欢它。
编辑:我在这里犯了一个错误,我假设
template<class =
first<void,
typename std::enable_if<has_check<Mixins>::value>::type...>>
SFINAE 会正确地消除 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();
};
但是,同样的技巧在 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;
}
同时强制 first<...>
和 enable_if<...>
扩展对 SFINAE 有效。 See it at Coliru.
关于c++ - 我该如何正确处理这个 SFINAE?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21948049/