gpt4 book ai didi

C++ 模板特化 - 避免重新定义

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:26:54 26 4
gpt4 key购买 nike

我想要一个接受不同类型参数的通用函数(或方法)。如果提供的类型有“一个”方法,函数应该使用它。如果它有“两个”方法,则该函数应该使用它。

这是无效代码:

#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;
}

是否可以使用SFINAE来实现?是否可以使用type_traits来实现?


澄清:

如果使用 SFINAE 可以做到这一点,我会更高兴。最好的情况是:使用第一个模板,如果失败则使用第二个。

检查方法是否存在只是一个例子。我真正想要的也是检查与其他类的兼容性。

任务可以改写:

  1. 如果该类支持第一个接口(interface),则使用它。
  2. 如果第一个接口(interface)失败,使用第二个接口(interface)。
  3. 如果两者都失败,则报告错误。

最佳答案

是的,这是可能的。在 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;
}

要点:

  1. 我们SFINAE关于func_dispatch_tag的第二个参数.编译器查看所有导致参数 <C, void> 的模板特化。 .由于当 SF 不发生时(即当 std::enable_if_tvoid 时)后者中的任何一个都“更专业”,因此它被选中。

  2. 特征的选定特化定义了一个标签,我们对其进行标签分派(dispatch)。标签分发取决于函数重载,而不是函数模板特化(不能部分特化)。

  3. 你可以定义一个回退函数(就像我做的那样),或者 static_assert .我们可以定义的标签数量仅受 int 范围的限制,因此扩展到其他成员只需添加另一个 func_dispatch_tag 即可。特化。

  4. 成员必须可访问,否则将发生 SF。此外,具有两个成员的类将导致歧义。请记住这一点。

关于C++ 模板特化 - 避免重新定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44257391/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com