2013-06-29 5 views
6

У меня есть этот код.Круглые петли и встроенные функции

#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 элементов.

Проблема в том, что когда я использую цикл на основе диапазона, он дает мне ошибки, упомянутые в коде. Но когда я использую обычное, все возвращается к норме. Я имею в виду, синтаксис для меня выглядит отлично, я не вижу проблемы. Я использую Visual Studio 2010.

Другая вещь, о которой я хочу спросить, это о встроенных функциях. В настоящее время я читаю C++ Primer Plus 6-е издание. Когда я знаю, когда функция слишком велика, чтобы быть встроенной? Существует ли стандарт того, насколько короче код? Или мы используем встроенные функции, когда мы «думаем», что все в порядке?

Спасибо, RobertEagle

+0

Не должна ли ваша вторая ошибка компилятора '[T = int]' вместо 'float'? – yzt

+0

Как насчет использования 'vector '? – Immueggpain

+0

Поплавок происходит из старого массива, который я объявил. –

ответ

7

Параметр 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]) 
    

    Это чистое, а также более гибкий, чем один из приведенных выше (и ниже единиц). В дополнение к прохождению массивов вы можете передать любой контейнер, если data[0] четко определен и означает, что он должен означать.

  • Или, если вы хотите, вы можете использовать std::array<T, 5> как:

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

Надежда, что помогает.

+0

Я считаю, что эта подпись будет работать с обычными массивами C и некоторыми другими контейнерами, в том числе 'std :: vector' и 'std :: array', и более разрешительна по размеру массивов, которая принимает: 'template inline decltype (C [0]) bigArry (C const & data) ' – yzt

+0

@yzt: Хорошая точка. :-) – Nawaz

+0

Я предлагаю его здесь (вместо другого ответа), чтобы вы могли добавить его к своему ответу, если хотите. Я думаю, что это лучший ответ, чем использование 'std :: array', поскольку он не требует нового заголовка. Но это, безусловно, более «громоздко». – yzt

6

Это потому, что типы массивов распада к указателям при использовании в качестве параметров функции или при передаче в качестве аргумента функции. Другими словами, ваша функция подпись эквивалентна:

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.

+0

Я считаю, что эта подпись будет работать с обычными массивами C и некоторыми другими контейнерами, включая' std :: vector 'и' std :: array' : 'template inline decltype (C [0]) bigArry (C const & data) {...}' – yzt

+0

@ Andy: На самом деле [правила для фигурных скобок] (http://stackoverflow.com/questions/ 11734861/when-can-outer-braces-be-omitted-in-an-initializer-list) иногда немного запутываются. Но то, что я сказал ранее, в этом случае не применяется. – Nawaz

+0

@Nawaz: Хорошо, спасибо за ссылку –

Смежные вопросы