当前位置: 首页 > 知识库问答 >
问题:

通过模板函数重载以正向顺序递归模板(关于std::tuple上的迭代)

束俊英
2023-03-14

我使用几种方法(出于好奇心)编写了关于std::tuple的迭代代码。我成功地使用了STD::ENABLE_IF方法、带有模板专门化的静态类函数、模板函数重载等。对于函数重载,我写了以下内容:

template<size_t N> struct SizeT{};

template<typename Tuple>
void print(Tuple, SizeT<0>){}

template<typename Tuple, size_t N>
void print(Tuple t, SizeT<N>)
{
    print(t,SizeT<N-1>());
    std::cout << std::get<N-1>(t) << ' ';
}

template<typename Tuple>
void print(Tuple t){
    print(t, SizeT<std::tuple_size<Tuple>::value>());
    std::cout << std::endl;
}
template<size_t N> struct SizeT{};

template<typename Tuple, size_t N>
void print(Tuple t, SizeT<N>) {
    std::cout << std::get<N>(t) << ' ';
    print(t,SizeT<N+1>());
}

template<typename Tuple>
void print(Tuple, SizeT< std::tuple_size<Tuple>::value >){
    std::cout << std::endl;
}

template<typename Tuple>
void print(Tuple t) {
    print(t,SizeT<0>());
}
call of overloaded 'print(std::tuple<A<int>&, A<int>&, A<long long int>&, A<long int>&>&, forward_first::SizeT<4u>)' is ambiguous
     print(t,SizeT<N+1>());
candidates are:
void forward_first::print(Tuple, forward_first::SizeT<N>) [with Tuple = std::tuple<A<int>&, A<int>&, A<long long int>&, A<long int>&>; unsigned int N = 4u]
 void print(Tuple t, SizeT<N>)
void forward_first::print(Tuple, forward_first::SizeT<std::tuple_size<Tuple>::value>) [with Tuple = std::tuple<A<int>&, A<int>&, A<long long int>&, A<long int>&>]
 void print(Tuple, SizeT< std::tuple_size<Tuple>::value >)
template<size_t N> struct SizeT{};

template<typename Tuple, size_t N>
void print(Tuple t, SizeT<N>) {
    std::cout << std::get<N>(t) << ' ';
    print(t,SizeT<N+1>());
}

template<typename Tuple>
void print(Tuple, SizeT<3>){
    std::cout << std::endl;
}

template<typename Tuple>
void print(Tuple t) {
    print(t,SizeT<0>());
}
template<typename Tuple>
void print(Tuple, SizeT< std::tuple_size<Tuple>::value >)

不再专业化了

template<typename Tuple, size_t N>
void print(Tuple t, SizeT<N>)

??

共有1个答案

万俟飞语
2023-03-14

问题是在std::tuple_size中有一个嵌套的,其作用令人惊讶。模板参数推导中的一个快速经验法则是,::之后的任何内容对编译器都是不透明的。这里令人惊讶的是,它不是发生在参数推导阶段本身(两个重载都有自己的参数正确推导),而是通过在重载解析阶段从另一个重载的合成参数推导出一个重载的参数。

14.8.2.4在偏序过程中推导模板参数[temp.duct.partial]

2使用两组类型来确定偏序。对于所涉及的每个模板,都有原始函数类型和转换后的函数类型。[注意:14.5.6.2中描述了转换类型的创建。-结束注意]演绎过程使用转换类型作为参数模板,另一个模板的原始类型作为参数模板。对于偏序比较中涉及的每种类型,该过程都要执行两次:一次使用转换后的模板-1作为参数模板,模板-2作为参数模板,再一次使用转换后的模板-2作为参数模板,模板-1作为参数模板。

// #1
template<typename Tuple>
void print(Tuple, SizeT< std::tuple_size<Tuple>::value >)

// #2
template<typename Tuple, size_t N>
void print(Tuple t, SizeT<N>)

很明显,第一个没有第二个模板参数可以推导,所以它至少和第二个重载一样专业。问题是第二个是否可以有它的n参数从第一个重载的合成的第二个参数推导出来。

参数推导没有发生的原因是一个非推导的上下文:

14.8.2.5从类型[temp.duct.type]推导模板参数

这意味着第二个重载也至少和第一个重载一样专门化。因此,重载解析无法选择一个,程序格式不正确。

注意:本问答中出现了类似的问题(只有n的某些值有3个重载和歧义)。

 类似资料:
  • 多亏了C11,我们收到了系列的仿函数包装器。不幸的是,我一直只听到关于这些新添加的不好的消息。最受欢迎的是它们非常慢。我测试了它,与模板相比,它们真的很糟糕。 111毫秒对1241毫秒。我认为这是因为模板可以很好地内联,而通过虚拟调用覆盖内部。 显然,在我看来,模板也有其问题: 它们必须以头的形式提供,这不是您在以封闭代码形式发布库时可能不希望做的事情, 因此,我可以假设s可以用作传递函子的事实标

  • 模板函数与重载是密切相关的。从函数模板产生的相关函数都是同名的,因此编译器用重载的解决方法调用相应函数。 函数模板本身可以用多种方式重载。我们可以提供其他函数模板,指定不同参数的相同函数名。例如,图12.2的printArray函数模板可以用另一printArray函数模板重载,用参数lowSubscriPt和highSubscript指定要打印的数组部分(见练习12.4)。 函数模板也可以用其他

  • 我目前有一个,但是为了灵活性,我希望能够分配一个lambda表达式,将作为映射中的值返回。 所以我创建了这个模板类: 并像这样使用它: IntelliSense提供了更多信息: 多个操作符“=”匹配这些操作数:function“valueorfunction::operator=(const std::function&other)[with T=std::wstring]”function“va

  • 从派生,并使用自定义结构对其进行专门化。也重载。然而,这才是问题的根源。如果我尝试编译它,我会得到: 显然,没有运算符“+”。但这是我的困惑…编译器被要求实现,因为这是继承的内容。但是,我从不使用或调用。那么编译器应该尝试生成这个基类函数吗?

  • 我有一个下面的类模板 给出以下错误: tmp.cc:19:27:错误:无法专门化(使用“template<>”)未专门化模板constexpr int MyClass::ArraySize<0>()的成员{return 0;} 有可能达到预期的行为吗?使用C++14/C++17特性的解决方案(我想如果-constexpr应该是可能的)受到欢迎,但不能解决我的特定问题,因为只有C++11可用。

  • 我目前正在研究可变参数模板,作为消化我一直在阅读的一些内容的一个小练习,我编写了一个小函数来输出其所有参数类型的名称: 令我惊讶的是,这是使用VC 12.0编译的,并且(似乎)工作得很好。 当只剩下一个参数时,由于重载之间的不确定性,我预计会出现错误,因为我了解到模板参数包可以为空/包含0个参数。 所以我的问题是为什么这行得通?“潜在的歧义”是如何解决的?两个函数的签名不是都只有一个参数吗?我觉得