【问题标题】:Range-based loop & Inline functions基于范围的循环和内联函数
【发布时间】:2018-06-27 07:21:24
【问题描述】:

我这里有这段代码。

#include <iostream>
using namespace std;

template <typename T> inline T bigArry(const T data[5])
{
    T level = data[0];
    for(T item : data) // error C2143: syntax error : missing ',' before ':' (1st)
    { //error C2143: syntax error : missing ';' before '{' (3rd)
        if(level<item){ level=item; }
    }
    return  level;
}

int main()
{
    int data[5]={//five variables}
    cout << bigArry(data);//see reference to function template instantiation 'T bigArry<int>(const T [])' being compiled with [ T=int] (2nd)

    return 0;
}

函数 bigArry() 返回 5 个元素的数组中的最大值。

问题是当我使用基于范围的循环时,它会给我代码中提到的错误。但是当我使用通常的 for 时,一切都会恢复正常。 我的意思是,对我来说语法看起来不错,我看不到问题所在。 我正在使用 Visual Studio 2010。

我想问的另一件事是关于内联函数。目前我正在阅读 C++ Primer Plus 第 6 版。我什么时候知道函数太大而无法内联?是否有代码应该多短的标准?或者,当我们“认为”没问题时,我们是否使用内联函数?

【问题讨论】:

  • 你的第二个编译器错误不应该是[ T=int ],而不是float吗?
  • vector&lt;T&gt;怎么样?
  • 浮点数来自我声明的旧数组。
  • @RobertEagle:我想通了。但您可能需要对其进行编辑以避免一些可能的混淆。
  • Visual Studo 2010 不支持 c++11 ranged base for 循环?它只有一个较旧的自定义语法“for (T item in data) {}”

标签: c++ loops c++11 inline


【解决方案1】:

参数data 不是函数模板中的数组。它实际上是一个指针。

这个功能

template <typename T> inline T bigArry(const T data[5])

一模一样和这个一样:

template <typename T> inline T bigArry(const T *data)

完全没有区别。

这就是你的代码出现编译错误的原因。

这里有几个修复:

  • 您可以通过引用接受参数,如:

    template <typename T> 
    inline T bigArry(const T (&data)[5]) //NOTE &
    

    应该可以。但这看起来很麻烦。也许,使用下一个。

  • 或者你可以使用这个(如@yzt 建议的那样):

    template <typename C> 
    inline auto bigArry(C const & data) -> decltype(data[0])
    

    这比上面的(和下面的)更干净,也更灵活。除了传递数组之外,您还可以传递 any 容器,只要 data[0] 定义明确并且意味着它应该表示的意思。

  • 或者,如果您愿意,您可以使用 std::array&lt;T, 5&gt; 作为:

    template <typename T> 
    inline T bigArry(const std::array<T,5> & data) 
    

希望对您有所帮助。

【讨论】:

  • 我相信这个签名将适用于纯 C 数组和其他一些容器,包括 std::vectors 和 std::arrays,并且在接受的数组大小方面更宽松:template &lt;typename C&gt; inline decltype(C[0]) bigArry(C const &amp; data)
  • 我建议在这里(而不是在另一个答案中),如果您认为合适,您可以将其添加到您的答案中。我认为这比使用std::array 更好,因为它不需要新的标题。但肯定更“麻烦”。
  • @yzt:完成。 (顺便说一句,decltype(C[0]) 没有任何意义;您的意思是所谓的尾随返回类型)。
  • 哦,对了!我想写的是decltype(C()[0]),但这也不正确。正如您所指出的,正确的方法是尾随-&gt; decltype(data[0])。谢谢。
【解决方案2】:

这是因为数组类型在用作函数参数或作为函数参数传递时会衰减为指针。换句话说,你的函数签名相当于

template <typename T> inline T bigArry(const T* data)

基于范围的for 循环将data 传递给全局std::begin()std::end() 函数,以便让迭代器(分别)指向容器的第一个和最后一个元素.

当然,没有接受指针的全局std::begin()std::end()函数,它们也无法有意义地定义:如何确定刚刚给出的容器的结尾指向其第一个元素的指针?

您可以使用 std::array 代替 C 数组(std::array 是围绕 C 数组的零开销包装器),并相应地修改您的调用函数:

template <typename T> inline T bigArry(std::array<T, 5> data)
//                                     ^^^^^^^^^^^^^^^^
{
    T level = data[0];
    for(T item : data)
    {
        if(level<item){ level=item; }
    }
    return  level;
}

int main()
{
    std::array<int, 5> data = {1,2,3,4,5};
//  ^^^^^^^^^^^^^^^^^^^^^^^
    std::cout << bigArry(data);

    return 0;
}

这是live example

【讨论】:

  • 我相信这个签名将适用于纯 C 数组和其他一些容器,包括 std::vectors 和 std::arrays:template &lt;typename C&gt; inline decltype(C[0]) bigArry(C const &amp; data) {...}
  • @Andy:实际上the rules for the curly-braces 有时有点令人困惑。但我之前所说的不适用于这种情况。
  • 我以这种方式使用花括号,因此我可以使用所有内容都聚集在一起的概念。这对我来说更容易。
  • @AndyProwl:如果您认为合适,我建议您在此处(而不是在我自己的答案中)将其添加到您的答案中。我认为这是一个比使用std::array 更好的解决方案,因为它不需要新的标头。
  • 顺便说一句,我在第一条评论中犯了一个错误(正如@Nawaz 在另一个答案的评论部分中指出的那样。)希望正确的方法是template &lt;typename C&gt; inline auto bigArry(C const &amp; data) -&gt; decltype(data[0]) {...}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 2014-12-06
相关资源
最近更新 更多