c++ - decltype的非终止递归使用

标签 c++ templates c++11 recursion

由于无限的编译时递归,以下代码的编译存在问题。 Clang 3.6.0 给出了有关递归模板实例化深度的错误,并且不会终止;而 GCC 4.9.2 保持沉默,也不会终止。

这是一个比我最初遇到的例子更简单的例子,bar 的第二个重载当然可以被赋予 int 作为返回类型;在这种情况下,第一个重载被选择用于调用 main 中的 bar;正如我最初希望的那样。为什么 decltype 的应用程序没有解析到专门用于 Foo 的第一个重载?

Foo 的第二个(默认)模板参数似乎在这里隐藏了关于递归问题的更详细的消息。这在原始上下文中很有用。

template <typename T, typename A = T>
struct Foo {};

template <typename T, typename A>
int bar(const Foo<T,A> &x) { return 0; }

template <typename T>
auto bar(const T &x)
 -> decltype(bar(Foo<T>{})){    
    return   bar(Foo<T>{});    
}

int main(int argc, char *argv[])
{
  Foo<char> f;    
  bar(f);

  return 0;
}

最佳答案

这会失败,因为 decltype 表达式需要为那些参数计算出 bar 的返回类型,所以它需要实例化所有 bar 模板,其中涉及查看 decltype 表达式,该表达式需要为这些参数计算出 bar 的返回类型,因此它需要实例化所有 bar templates...我相信你可以想象这最终会导致编译器崩溃。

在 C++14 中,我们可以省略尾随返回类型来避免所有这些工作。在 C++11 中,当 TFoo 时,我们可以禁用该重载:

namespace detail {
    template <typename T>
    struct is_foo : std::false_type{};
    template <typename T, typename A>
    struct is_foo<Foo<T,A>> : std::true_type{};
}
template <typename T>
using is_foo = detail::is_foo<typename std::decay<T>::type>;

template <typename T, typename A>
int bar(const Foo<T,A> &x) { return 0; }

template <typename T, 
   typename = typename std::enable_if<!is_foo<T>::value>::type>
auto bar(const T &x)
 -> decltype(bar(Foo<T>{})){    
    Foo<T> b{};
    return bar(b);    
}

关于c++ - decltype的非终止递归使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32350698/

相关文章:

java - 将可绘制对象作为字节数组发送到android的jni部分

c++ - 通过指针进行的内存复制有时会丢失数据

C++ 模板化友元类

c++ - 什么 c++ 语法适合通过枚举参数作为模板参数实现嵌套类的函数?

c++ - 非推导上下文中模板参数推导的解决方法

c++ - 如何 `decltype` 仿函数运算符()?

c++ - 在另一个线程正在运行的情况下退出应用程序时出错

C++ - 实现快速排序的问题

c++ - 如何检查文件是否已被另一个 C++ 应用程序打开?

c++ - 如何为 std::vector 创建一个 shared_ptr?