C++ 递归构建变量函数的返回类型时的奇怪行为

C++ 递归构建变量函数的返回类型时的奇怪行为,c++,templates,c++11,variadic-functions,C++,Templates,C++11,Variadic Functions,这可能是一个非常简单的解释,但我会尽可能多地提供背景资料,以防我错了。对于如此冗长,我深表歉意。我使用的是gcc4.5,我意识到c++0x支持在某种程度上仍然是实验性的,但我将在假设我看到的行为有一个与错误无关的原因的基础上采取行动 我正在试验可变函数模板。最终目标是用std::pair构建一个cons列表。它不是一个自定义类型,只是一个成对对象的字符串。构造列表的函数必须以某种方式递归,最终返回值取决于递归调用的结果。作为添加的扭曲,连续参数在插入列表之前将添加在一起。如果我通过[1,2,3,

这可能是一个非常简单的解释,但我会尽可能多地提供背景资料,以防我错了。对于如此冗长,我深表歉意。我使用的是gcc4.5,我意识到c++0x支持在某种程度上仍然是实验性的,但我将在假设我看到的行为有一个与错误无关的原因的基础上采取行动

我正在试验可变函数模板。最终目标是用
std::pair
构建一个cons列表。它不是一个自定义类型,只是一个成对对象的字符串。构造列表的函数必须以某种方式递归,最终返回值取决于递归调用的结果。作为添加的扭曲,连续参数在插入列表之前将添加在一起。如果我通过[1,2,3,4,5,6],最终结果应该是{1+2,{3+4,5+6}

我最初的尝试相当幼稚。具有两个重载的函数Build。其中一个取了两个相同的参数并简单地返回它们的总和。另一个采用了两个参数和一个参数包。返回值是由两个集合参数和递归调用组成的一对。回想起来,这显然是一个有缺陷的策略,因为在我试图确定其返回类型时没有声明函数,因此它别无选择,只能解析为非递归版本

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

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

违规代码:

static auto Go(const Type& t0, const Type& t1, const Types&... rest)
    -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))>
非结构化解决方案:

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;
}
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;
}
结构解决方案:

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;
}
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;
}
模板
struct-BuildStruct;
模板
结构构建结构{
静态类型Go(常量类型&t0,常量类型&t1){return t0+t1;}
};
模板
结构构建结构{
静态自动转到(常量类型和t0、常量类型和t1、常量类型和…rest)
->std::pair{
返回std::pair
(t0+t1,BuildStruct::Go(rest…);
}
};
模板
void Execute(常量类型和…t){

看了这些评论,似乎很清楚这是一个非常本地化的错误,在特定版本的G++,这就是所有的答案。

现在无法尝试,但可能是延迟返回类型扣除仍然失败。在第二种情况下,您应该能够定义返回类型:
typedef std::配对结果类型;
(适用于第一个专门化)并使用它们:
静态结果类型Go(…)
天哪,这有很多要读的:)您的“非结构化解决方案”代码与我的GCC版本(4.4.3)编译得很好。我找不到该代码有任何错误,但我听说GCC4.5中有几个偏序缺陷。这似乎是其中之一(它可能会失败,因为在“const char,const char”的情况下,它错误地选择了可变模板,然后会尝试依次调用BuildFunction,而不带任何参数-因此一路失败)有迹象表明,在特定版本的gcc中,这是一个非常局部的错误。因此,我投票认为过于局部化。对于一个需要CS学位才能理解的问题,解释并不是一件简单的事。我一个月前得出了这个结论,感谢您的回答,这样我才能让它消失:)
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>'