C2977:“std::tuple”:模板参数过多 (MSVC11)

Posted

技术标签:

【中文标题】C2977:“std::tuple”:模板参数过多 (MSVC11)【英文标题】:C2977: 'std::tuple' : too many template arguments (MSVC11) 【发布时间】:2012-01-06 15:46:47 【问题描述】:

我正在尝试使用 Visual C++ 11 构建 googletest,但以下代码会导致错误

template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6, typename T7, typename T8, typename T9>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t, // <-- error C2977
             ::std::ostream* os) 
  PrintTupleTo(t, os);

这是一个错误文本:

f:\gtest-1.6.0\include\gtest\gtest-printers.h(550): error C2977: 'std::tuple' : too many template arguments
  c:\program files (x86)\microsoft visual studio 11.0\vc\include\utility(72) : see declaration of 'std::tuple'

还有utility-file的第72行:

template<class = _Nil, _MAX_CLASS_LIST>
   class tuple; // Line 72

std::tuple 有什么问题以及如何解决?

(顺便说一句:我尝试将 std::tr1::tuple 更改为 std::tuple 失败)

【问题讨论】:

你包括&lt;tuple&gt;吗? Visual Studio 的std::tuple 最多支持 10 种类型,因此应该可以编译。它也应该通过 using 语句在 std:: 命名空间中,这让我觉得要么你没有包含 &lt;tuple&gt;,要么 VS11 有问题。 一个提醒,如果你有一个超过 5 个成员的元组。为了便于阅读,您可能更喜欢使用命名成员而不是 get(aTuple) 定义一个类。对于大多数情况,默认复制 ctor 和 operator= 就足够了。 【参考方案1】:

在msdn blog 中查看此条目。 VC++11 不支持可变参数模板。他们有一些他们称之为人造可变参数的东西。向下滚动,你会看到一个关于 Faux variadics 的段落,它讨论了元组。在该段中,他们说默认的最大参数数为 5。您可以将其增加到 10:

您可以在 5 到 10 之间定义 _VARIADIC_MAX 项目范围(默认为 5)。增加它会使编译器消耗更多内存,并且可能需要您使用 /Zm 选项为 PCHe 保留更多空间。

他们说他们有一个修复方法可以再次将默认值设为 10。

【讨论】:

他们应该只实现可变参数模板,而不是修复被设计破坏的东西。 @rubenvb 当它发生重大变化并且人们大喊您不支持某些功能仅仅因为您支持“旧”变体时,您如何实施? C++ 草案将参数的最小数量设置为 10。事实上,这是 GCC 作者所写的“在 GCC 标准库实现中,过多的编译时间迫使将支持的最大参数数量从原来的 20 个恢复到 10 个——标准草案 [10] 允许的最小值。" (jot.fm/issues/issue_2008_02/article2) @Ark-kun 您是否阅读过答案或它链接到的博客文章? MSVC 2012 没有可变参数模板(除非您想尝试实验性的 11 月 CTP,在这种情况下,如果没有真正的可变参数模板支持,库标题可能仍然会被破坏)。我的评论不是关于模板参数的数量,而是实现本身。 2008 年的文章在 2013 年并不是我感兴趣的。 @ruvenvb 产品开发有一定的发展势头。 Visual Studio 2012 在开始开发时正确实现了标准草案。然后,C++ 草案发生了变化。 C++11 标准于 2011 年 8 月发布(比 MSDN 博客文章早一个月),当时在产品周期中重新实现和重新测试可变参数模板等非常复杂的功能为时已晚。我的观点是“当标准刚刚改变(或尚未发布)时,不要因为“非标准”功能实现而责备产品。”【参考方案2】:

在 Visual Studio 2012 (VC11) 中,_VARIADIC_MAX 在标头 &lt;xstddef&gt; 中默认定义为 5:

#if !defined(_VARIADIC_MAX)
 #define _VARIADIC_MAX  5

#elif _VARIADIC_MAX < 5 || 10 < _VARIADIC_MAX
 #error _VARIADIC_MAX must be between 5 and 10, inclusive
#endif /* !defined(_VARIADIC_MAX) */

如果你有多个VC11项目在一个解决方案中包含&lt;tuple&gt;,最好将宏设置为all by

1) Shift 单击以选择解决方案中的所有 C++ 项目

2) 属性、C/C++、预处理器、所有配置、所有平台、预处理器定义、&lt;Edit&gt;

3) 在&lt;different options&gt; 之前添加一行

_VARIADIC_MAX=10;

你可以把10改成6~10之间的任意数字。

【讨论】:

blogs.msdn.com/b/vcblog/archive/2013/06/28/… 我们在 Visual C++ 2012 中将无穷大从 10 降低到 5,以缩短大多数用户的编译时间(我们提供了一种通过宏 _VARIADIC_MAX 请求旧限制 10 的方法)。在 Visual C++ 2013 中,我们彻底消除了虚假的可变参数宏。如果你想要 50 种类型的元组,你现在就可以拥有它们。此外,我很高兴地宣布,将 STL 切换到真正的可变参数模板可以缩短编译时间并减少编译器内存消耗。 这是迄今为止最好和最干净的答案,你是应该赢得那个勾号的人。非常感谢朋友。 别忘了加分号_VARIADIC_MAX=10;【参考方案3】:

在 gtest.h 中将 GTEST_HAS_TR1_TUPLE 设置为 0 对我有帮助

更新:当然,侵入性较小的方法是定义一个预编译器标志 GTEST_HAS_TR1_TUPLE=0。检查有关_VARIADIC_MAX=10 的答案 - 解决了另一半问题。

【讨论】:

我喜欢这个答案,不会影响其余代码(:(P.s. microsoft 很烂)【参考方案4】:

在 Visual Studio 2013 中,std::tuple 不再使用_VARIADIC_MAX,现在使用实际的可变参数templates,所以这个问题应该没有了。

如果你在 2013 年遇到它,这意味着你包含了错误的标准库。

【讨论】:

【参考方案5】:

这在 r675 版本中已修复。见https://code.google.com/p/googletest/source/detail?r=675

【讨论】:

【参考方案6】:

以下行添加到您的 cmake 文件中

add_definitions(/D_VARIADIC_MAX=10)

【讨论】:

【参考方案7】:

要在 Visual Studio 2012 中使用 GoogleTest,您应该在使用它的项目的 Properties->C/C++->Preprocessor->PreprocessorDefinitions 下设置 _VARIADIC_MAX=10。 否则您可能会遇到以下错误 错误 C2977:“std::tuple”:模板参数太多

【讨论】:

以上是关于C2977:“std::tuple”:模板参数过多 (MSVC11)的主要内容,如果未能解决你的问题,请参考以下文章

漂亮的打印 std::tuple

如何使用可变参数模板 c ++ 泛化此函数

std::tuple

在std :: tuple中转换元素

std::get(std::tuple)

C++ 中的 std::pair 和 std::tuple