首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以递归方式为变量函数构建返回类型时的奇怪行为

以递归方式为变量函数构建返回类型时的奇怪行为
EN

Stack Overflow用户
提问于 2010-04-19 16:39:18
回答 1查看 1.7K关注 0票数 23

这可能是一个非常简单的解释,但我将尽可能多地讲述背景故事,以防我错了。非常抱歉,我太罗嗦了。我正在使用gcc4.5,并且我意识到c++0x支持仍然是实验性的,但我将假设我看到的行为是有与bug无关的原因的。

我正在试验各种函数模板。最终目标是在std::pair之外构建一个cons-list。它并不意味着是一个自定义类型,只是一个由pair对象组成的字符串。构造列表的函数必须以某种方式递归,最终的返回值取决于递归调用的结果。作为添加的扭曲,连续的参数在插入到列表中之前被添加在一起。因此,如果我传递1,2,3,4,5,6,最终结果应该是{1+2,{3+4,5+6}}。

我最初的尝试相当天真。具有两个重载的函数Build。其中一个接受了两个相同的参数,并简单地返回了它们的和。另一个采用两个参数和一个参数包。返回值是由两个设置参数和递归调用组成的对。回想起来,这显然是一个有缺陷的策略,因为当我试图弄清楚函数的返回类型时,函数没有声明,所以它别无选择,只能解析为非递归版本。

我能理解。我感到困惑的是第二次迭代。我决定让这些函数成为模板类的静态成员。函数调用本身不是参数化的,而是整个类都参数化。我的假设是,当递归函数试图生成它的返回类型时,它会用它自己的静态函数实例化一个全新版本的结构,然后一切都会自己解决。

结果是:“错误:对BuildStruct<double, double, char, char>::Go(const char&, const char&)的调用没有匹配的函数”

有问题的代码:

代码语言:javascript
复制
static auto Go(const Type& t0, const Type& t1, const Types&... rest)
    -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))>

我的困惑来自于这样一个事实,即BuildStruct的参数应该始终与发送给BuildStruct::Go的参数的类型相同,但是在错误代码中,Go缺少了最初的两个双精度参数。这里我漏掉了什么?如果我最初关于如何选择静态函数的假设是不正确的,为什么它要尝试调用错误的函数,而不是根本找不到函数呢?它似乎只是随意地混合类型,我就是想不出为什么。如果我向初始调用添加额外的参数,它总是深入到失败之前的最后一步,所以可以推测递归本身至少是部分工作的。这与最初的尝试形成了直接的对比,最初的尝试总是无法立即找到函数调用。

最终,我克服了这个问题,使用了一个相当优雅的解决方案,几乎不像前两个尝试中的任何一个。所以我知道怎么做我想做的事。我正在为我所看到的失败寻找一个解释。

完整的代码要遵循,因为我确信我的口头描述是不够的。如果您觉得有必要执行代码并亲自查看,请先执行一些样板文件。然后是第一次尝试,这是合理的失败,然后是第二次尝试,没有。

代码语言:javascript
复制
#include <iostream>
using std::cout;
using std::endl;

#include <utility>

template<typename T1, typename T2>
std::ostream& operator <<(std::ostream& str, const std::pair<T1, T2>& p) {
  return str << "[" << p.first << ", " << p.second << "]";
}

//Insert code here    

int main() {
  Execute(5, 6, 4.3, 2.2, 'c', 'd');
  Execute(5, 6, 4.3, 2.2);
  Execute(5, 6);

  return 0;
}

非结构化解决方案:

代码语言:javascript
复制
template<typename Type>
Type BuildFunction(const Type& t0, const Type& t1) {
  return t0 + t1;
}

template<typename Type, typename... Rest>
auto BuildFunction(const Type& t0, const Type& t1, const Rest&... rest)
      -> std::pair<Type, decltype(BuildFunction(rest...))> {
  return std::pair<Type, decltype(BuildFunction(rest...))>
                  (t0 + t1, BuildFunction(rest...));
}

template<typename... Types>
void Execute(const Types&... t) {
  cout << BuildFunction(t...) << endl;
}

由此产生的错误:

代码语言:javascript
复制
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]':
test.cpp:33:35:   instantiated from here
test.cpp:28:3: error: no matching function for call to 'BuildFunction(const int&, const int&, const double&, const double&, const char&, const char&)'

结构解决方案:

代码语言:javascript
复制
template<typename... Types>
struct BuildStruct;

template<typename Type>
struct BuildStruct<Type, Type> {
  static Type Go(const Type& t0, const Type& t1) { return t0 + t1; }
};

template<typename Type, typename... Types>
struct BuildStruct<Type, Type, Types...> {
  static auto Go(const Type& t0, const Type& t1, const Types&... rest)
        -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> {
    return std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))>
               (t0 + t1, BuildStruct<Types...>::Go(rest...));
  }
};

template<typename... Types>
void Execute(const Types&... t) {
  cout << BuildStruct<Types...>::Go(t...) << endl;
}

由此产生的错误:

代码语言:javascript
复制
test.cpp: In instantiation of 'BuildStruct<int, int, double, double, char, char>':
test.cpp:33:3:   instantiated from 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]'
test.cpp:38:41:   instantiated from here
test.cpp:24:15: error: no matching function for call to 'BuildStruct<double, double, char, char>::Go(const char&, const char&)'
test.cpp:24:15: note: candidate is: static std::pair<Type, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...))> BuildStruct<Type, Type, Types ...>::Go(const Type&, const Type&, const Types& ...) [with Type = double, Types = {char, char}, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...)) = char]
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]':
test.cpp:38:41:   instantiated from here
test.cpp:33:3: error: 'Go' is not a member of 'BuildStruct<int, int, double, double, char, char>'
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-06-16 05:40:26

阅读评论,这似乎足够清楚,这是特定版本的G++中的一个非常本地化的错误,这就是所有的答案。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2666160

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档