haa*_*ael 4 c++ templates sfinae type-traits template-specialization
我想要一个接受不同类型参数的泛型函数(或方法).如果提供的类型具有"one"方法,则该函数应使用它.如果它有'两个'方法,该函数应该使用它.
这是无效的代码:
#include <iostream>
template<typename Type> void func(Type t)
{
t.one();
}
template<typename Type> void func(Type t) // redefinition!
{
t.two();
}
class One
{
void one(void) const
{
std::cout << "one" << std::endl;
}
};
class Two
{
void two(void) const
{
std::cout << "two" << std::endl;
}
};
int main(int argc, char* argv[])
{
func(One()); // should print "one"
func(Two()); // should print "two"
return 0;
}
Run Code Online (Sandbox Code Playgroud)
是否可以使用SFINAE?是否可以使用type_traits?
澄清:
如果可以使用SFINAE,我会更高兴.最好的情况是:使用第一个模板,如果失败则使用第二个模板.
检查方法存在只是一个例子.我真正想要的还是检查与其他类的兼容性.
任务可以改写:
是的,这是可能的.在C++ 11中,它甚至相对容易.
#include <iostream>
#include <type_traits>
template<class, typename = void>
struct func_dispatch_tag :
std::integral_constant<int, 0> {};
template<class C>
struct func_dispatch_tag<C,
std::enable_if_t<std::is_same<decltype(&C::one), void (C::*)() const>::value>
> : std::integral_constant<int, 1> {};
template<class C>
struct func_dispatch_tag<C,
std::enable_if_t<std::is_same<decltype(&C::two), void (C::*)() const>::value>
> : std::integral_constant<int, 2> {};
template<class C>
void func(C const&, std::integral_constant<int, 0>) {
std::cout << "fallback!\n";
}
template<class C>
void func(C const &c, std::integral_constant<int, 1>) {
c.one();
}
template<class C>
void func(C const &c, std::integral_constant<int, 2>) {
c.two();
}
template<class C>
void func(C const &c) {
func(c, func_dispatch_tag<C>{});
}
struct One
{
void one(void) const
{
std::cout << "one\n";
}
};
struct Two
{
void two(void) const
{
std::cout << "two\n";
}
};
struct Three {};
int main(int argc, char* argv[])
{
func(One()); // should print "one"
func(Two()); // should print "two"
func(Three());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
重点:
我们SFINAE上的第二个参数func_dispatch_tag
.编译器查看导致参数的所有模板特化<C, void>
.由于任何后者是"更专门的"时,不会发生SF(即,当std::enable_if_t
是void
),它被选择的.
所选择的特征特化定义了一个标签,我们对其进行标签调度.标签分派取决于函数重载,而不是函数模板特化(不能部分专门化).
您可以定义回退功能(就像我做的那样),或者static_assert
.我们可以定义的标签数量仅受int的范围限制,因此扩展到其他成员只需添加另一个特化func_dispatch_tag
.
该成员必须是可访问的,否则将发生SF.此外,具有两个成员的类将导致歧义.记住这一点.