Использование std:array
От: Андрей Е  
Дата: 01.03.12 05:50
Оценка:
В новом стандарте в библиотеке появилась безопасная обёртка вокруг встроенного массива std::array. Сделано вроде как просто и эффективно. Даже инициализировать его можно так же как встроенный массив.
Всё бы хорошо, но есть одна проблема. Этот шаблонный класс требует два параметра: тип хранимого значения и размер. И если я хочу например передать array в фукнцию, даже по ссылке или указателю, я должен в типе аргумента функции указать оба параметра шаблона: тип и размер.
Пример:
#include <iostream>
#include <array>

void f(const std::array<int, 5>& x) {
    for (int y : x)
        std::cout << y << ", ";
    std::cout << '\n';
}

int main() {
    std::array<int,5> a={1,2,3};    
    f(a);
    return 0;
}

Это очень неудобно: нужно плодить волшебную константу везде, где используется массив и заменять ее ручками когда в массив добавляется ещё одно значение. При этом в функции эта константа никак не используется.

Подскажите пожалуйста, можно ли как-то обойти эту проблему?
Re: Использование std:array
От: Gorilla  
Дата: 01.03.12 05:57
Оценка: +2
Здравствуйте, Андрей Е, Вы писали:

АЕ>Подскажите пожалуйста, можно ли как-то обойти эту проблему?

typedef?
Re: Использование std:array
От: 0x7be СССР  
Дата: 01.03.12 05:58
Оценка:
Здравствуйте, Андрей Е, Вы писали:

АЕ>Подскажите пожалуйста, можно ли как-то обойти эту проблему?

1. Определить именованную константу.
2. Определить свой тип массива, определяющего размерность.
Re: Использование std:array
От: uncommon Ниоткуда  
Дата: 01.03.12 06:02
Оценка:
Здравствуйте, Андрей Е, Вы писали:

АЕ>Это очень неудобно: нужно плодить волшебную константу везде, где используется массив и заменять ее ручками когда в массив добавляется ещё одно значение. При этом в функции эта константа никак не используется.


АЕ>Подскажите пожалуйста, можно ли как-то обойти эту проблему?


Ты думаешь, когда ты делаешь "for (auto y: x)", откуда этот цикл знает, сколько элементов в массиве x? Этот цикл эквивалентен:
for (auto it = x.begin(), end = x.end(); it != end; ++it) { auto y = *it; ... }


А уж 'x.end() === x.begin() + 5'. Так что число элементов, там используется все таки.

Если хочешь, чтобы твой код не зависел от числа элементов, передавай в функции итераторы на начало и конец:
template <typename Iterator>
void f(Iterator begin, Iterator end) { ... }

int main()
{
    std::array<int,5> a={1,2,3};    
    f(begin(a), end(a));
}


Или даже просто указатели, если тебе итераторы не подходят.
Re: Использование std:array
От: wander  
Дата: 01.03.12 07:07
Оценка:
Здравствуйте, Андрей Е, Вы писали:

АЕ> Подскажите пожалуйста, можно ли как-то обойти эту проблему?


template <typename T, size_t N>
void f(const std::array<T, N> & x) {
        for (int y : x)
                std::cout << y << ", ";
        std::cout << '\n';
}

м?
avalon 1.0rc3 build 426, zlib 1.2.3
Re: Использование std:array
От: 0xDEADBEEF Ниоткуда  
Дата: 01.03.12 07:22
Оценка:
Здравствуйте, Андрей Е, Вы писали:

АЕ>Подскажите пожалуйста, можно ли как-то обойти эту проблему?

Можно.

Определяем велосипед:
template<class... T> struct _Len;
template<class T, class... TT> struct _Len<T,TT...>
    { static const std::size_t value = 1 + _Len<TT...>::value; };
template<class T> struct _Len<T>
    { static const std::size_t value = 1; };

template<class T, class... A> inline
std::array<T,_Len<A...>::value> arrayof(A&&... a)
    { std::array<T,_Len<A...>::value> r = { a... }; return r; }


Используем:
template<class T, std::size_t N>
void f(const std::array<T,5>& x) {
    for (T y : x)
        std::cout << y << ", ";
    std::cout << '\n';
}

int main()  
{
    auto arr = asarray<int>(1,2,3);
    f(arr);
    f( asarray<insigned short>(4,5,6) );
}


ЗЫ. И, разумеется, Visual C++ sucks. GCC rulez, ибо шаблоны с переменным числом аргументов.
ЗЗЫ. Конечно, можно отсосать у Visual C++ и написать кучу перегруженных asarray(), но мне лень а вам — неплохое задание для общего развития
__________
16.There is no cause so right that one cannot find a fool following it.
Re[2]: Использование std:array
От: Сыроежка  
Дата: 01.03.12 08:31
Оценка: +1
Здравствуйте, wander, Вы писали:

W>Здравствуйте, Андрей Е, Вы писали:


АЕ>> Подскажите пожалуйста, можно ли как-то обойти эту проблему?


W>
W>template <typename T, size_t N>
W>void f(const std::array<T, N> & x) {
W>        for (int y : x)
W>                std::cout << y << ", ";
W>        std::cout << '\n';
W>}
W>

W>м?

Только надо внутренний циул исправитьЮ так как массив не обязательно имеет тип int

template <typename T, size_t N>
void f(const std::array<T, N> & x) {
        for ( const auto & y : x )
                std::out << y << ", ";
        std::cout << std::endl;
}
Меня можно встретить на www.cpp.forum24.ru
Re: Использование std:array
От: Сыроежка  
Дата: 01.03.12 08:46
Оценка:
Здравствуйте, Андрей Е, Вы писали:

АЕ>В новом стандарте в библиотеке появилась безопасная обёртка вокруг встроенного массива std::array. Сделано вроде как просто и эффективно. Даже инициализировать его можно так же как встроенный массив.

АЕ>Всё бы хорошо, но есть одна проблема. Этот шаблонный класс требует два параметра: тип хранимого значения и размер. И если я хочу например передать array в фукнцию, даже по ссылке или указателю, я должен в типе аргумента функции указать оба параметра шаблона: тип и размер.
АЕ>Пример:
АЕ>
АЕ>#include <iostream>
АЕ>#include <array>

АЕ>void f(const std::array<int, 5>& x) {
АЕ>    for (int y : x)
АЕ>        std::cout << y << ", ";
АЕ>    std::cout << '\n';
АЕ>}

АЕ>int main() {
АЕ>    std::array<int,5> a={1,2,3};    
АЕ>    f(a);
АЕ>    return 0;
АЕ>}
АЕ>

АЕ>Это очень неудобно: нужно плодить волшебную константу везде, где используется массив и заменять ее ручками когда в массив добавляется ещё одно значение. При этом в функции эта константа никак не используется.

АЕ>Подскажите пожалуйста, можно ли как-то обойти эту проблему?


Вы можете работать с ним точно также, как вы работаете с массивами в С, то есть испольуя указатель на первый элемент массива, который получается с помощью функции члена класса data, и размер массива, который получается с помощью функции члена класса size.

например,

#include <iostream>
#include <array>
#include <algorithm>

void f( const int a[], size_t n )
{
    std::for_each( a, a + n, 
        []( int x ) { std::cout << x << ", "; } );
    std::cout << std::endl;
}

int main()
{
    std::array<int,5> a={1,2,3};    

    f( a.data(), a.size() );

    return 0;
}
Меня можно встретить на www.cpp.forum24.ru
Re[2]: Использование std:array
От: innochenti  
Дата: 01.03.12 09:30
Оценка:
Здравствуйте, 0xDEADBEEF, Вы писали:

DEA>Здравствуйте, Андрей Е, Вы писали:


DEA>template<class T, class... TT> struct _Len<T,TT...>

DEA> { static const std::size_t value = 1 + _Len<TT...>::value; };

правильно ли я понимаю, что здесь определяется специализация для головы списка типов, и остальной части?
а какая тогда будет вызвана специлизация здесь _Len<TT...>::value ? как оно понимает что надо выбрать вторую специализацию?
Re[2]: Использование std:array
От: Alexey F  
Дата: 01.03.12 09:52
Оценка: 4 (2)
Здравствуйте, 0xDEADBEEF, Вы писали:

DEA>Определяем велосипед:

(skipped)
Зачем Len, когда есть sizeof...? Workaround для какой-то версии компилятора?

// static_cast к типу массива - чтобы не ругался, когда мы int -> short int присваиваем,
// T внутри static_cast менять, вроде, не надо,
// а дополнительные скобки - так, чтобы мой gcc не ругался warning'ми:
template<class T, class... A>
inline std::array<T,sizeof...( A )> arrayof(A&&... a) {
    return {{ static_cast<T>( a )... }};
}
Re[2]: Использование std:array
От: Masterkent  
Дата: 01.03.12 10:02
Оценка: 1 (1) +2
wander:

АЕ>> Подскажите пожалуйста, можно ли как-то обойти эту проблему?


W>
W>template <typename T, size_t N>
W>void f(const std::array<T, N> & x) {
W>        for (int y : x)
W>                std::cout << y << ", ";
W>        std::cout << '\n';
W>}
W>

W>м?

В шаблоне-то можно и без std::array обойтись:

template <class InputRange>
    void f(InputRange const &range)
{
    auto current = std::begin(range);
    auto const ending = std::end(range);

    if (current != ending)
    {
        std::cout << *current;
        while (++current != ending)
            std::cout << ", " << *current;
    }
    std::cout << '\n';
}

template <class T>
    void f(std::initializer_list<T> init_list)
{
    f<std::initializer_list<T>>(init_list);
}
Re[3]: Использование std:array
От: 0xDEADBEEF Ниоткуда  
Дата: 01.03.12 18:06
Оценка: 1 (1)
Здравствуйте, Alexey F, Вы писали:

AF>Зачем Len, когда есть sizeof...? Workaround для какой-то версии компилятора?

Если честно, наличие вариадик sizeof как-то пробежало мимо внимания. А ручонки сами по себе накропали рекурсивный шаблон
Спасибо за напоминание.

AF>// static_cast к типу массива - чтобы не ругался, когда мы int -> short int присваиваем,
//Тогда, лучше std::forward, коль скоро мы rvalue references используем и украсим это дело constexpr.
//Он тут, конечно, как собаке пятая нога, но красяво
template<class T, class... A> inline
constexpr array<T,sizeof...( A )> arrayof(A&&... a)
    { return {{ std::forward<T>( a )... }}; }
__________
16.There is no cause so right that one cannot find a fool following it.
Re[2]: Использование std:array
От: b-3 Россия  
Дата: 01.03.12 18:26
Оценка:
Здравствуйте, uncommon, Вы писали:

U>Если хочешь, чтобы твой код не зависел от числа элементов, передавай в функции итераторы на начало и конец:


Это случаем не Вы писали STL?

U>Или даже просто указатели, если тебе итераторы не подходят.

К счастью, похоже что нет
Забанен с формулировкой "клинический дисидент".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.