我遇到了根据参数包的特性启用/禁用重载的问题。这是我想要回答的另一个问题。我有一个静态go()
函数,如果所有Mixins
类型都有静态check()
方法,则应调用该函数。同样,如果go()
包不具有Mixins
方法,则应该调用另一个静态check()
方法。我尝试创建基于此策略启用的重载,但出于某种原因,当我调用它时,它会选择第二次重载,尝试调用handle()
:
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()
的成员。这一直困扰着我,但我无法找到解决办法。我该如何解决这个问题?如何根据参数包正确协调重载决策?
答案 0 :(得分:1)
你没有什么可以区分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 out。
编辑:我在这里犯了一个错误,我认为
template<class =
first<void,
typename std::enable_if<has_check<Mixins>::value>::type...>>
正确SFINAE远离foo
的重载。但是,此处的错误不是替换失败,因为未命名的函数模板参数的默认值不依赖于函数模板的参数。通常,当您在类型T
上参数化类并且希望基于f
的某些属性约束成员函数T
时,可以使用{{1的别名强制该依赖项}}:
T
然而,相同的技巧在OP的情况下不起作用,因为OP的类在包上参数化,并且无法为参数包提供默认值。我们必须更加棘手:
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;
}
和first<...>
展开对SFINAE有效。 See it at Coliru.