инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 14:50
Оценка:
приветствую!

есть массив a, и массив b .
нужно, инициализировать массив c следующим образом(в псевдокоде): static const char c[] = a + '-' + b;

сабж, вообще, возможен?

благодарен.

зы
далее, переменная c будет использоваться для разбора, опять же в compile-time.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: инициализация массива байт в compile-time
От: rg45 СССР  
Дата: 19.03.13 15:23
Оценка:
Здравствуйте, niXman, Вы писали:

X>приветствую!

X>есть массив a, и массив b .
X>нужно, инициализировать массив c следующим образом(в псевдокоде): static const char c[] = a + '-' + b;
X>сабж, вообще, возможен?
X>благодарен.
X>зы
X>далее, переменная c будет использоваться для разбора, опять же в compile-time.


Сначала не мешало бы договориться, что мы понимаем под compile-time массивом. Как я понимаю, это такой массив, значения элементов которого также доступны в компайл-тайм. И если, к примеру, это массив int, то мы можем элементы этого массива использовать при определении элементов перечислений и параметризовать ими шаблоны? Это не возможно. В этом понимании компайл-тайм массивов не существует как таковых.

Их можно симулировать с помощью variadic темплейтов:

template<typename T, T...> struct CTArray;

typedef CTArray<char, 'a', 'b', 'c'> A;
typedef CTArray<char, 'x', 'y', 'z'> B;

typedef typename A::Combine<B>::Type C;

Такое решение не подходит?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: инициализация массива байт в compile-time
От: Evgeny.Panasyuk Россия  
Дата: 19.03.13 15:23
Оценка:
Здравствуйте, niXman, Вы писали:

X>есть массив a, и массив b .

X>нужно, инициализировать массив c следующим образом(в псевдокоде): static const char c[] = a + '-' + b;

Как у тебя определенны массив a и b? Как обычные? Или например mpl::string?
Из двух mpl::string можно инициализировать char c[]
Автор: rg45
Дата: 25.10.12
compile time.
Re[2]: инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 16:02
Оценка:
a и b — обычные массивы байт. хотелось бы, чтоб так оно и осталось.
просто подумал, что возможно есть какой-то способ инициализировать обычные массивы, другими массивами байт.
типа: static const char c[] = {a..., b...};

mpl::string для этого тянуть не хотелось бы.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: инициализация массива байт в compile-time
От: Evgeny.Panasyuk Россия  
Дата: 19.03.13 16:19
Оценка:
Здравствуйте, niXman, Вы писали:

X>mpl::string для этого тянуть не хотелось бы.


тогда нужно сделать функцию, которая возвращает i'ый элемент нового массива.
Например тут:
template<typename ...Ratio>
double FixedArray<Ratio...>::instance[size] = { ratio_to_double<Ratio>()... };

ratio_to_double это обычная функция:
template<typename Ratio>
double ratio_to_double()
{
    return double(Ratio::num)/Ratio::den;
}

Таким же образом можно склеить массивы, но это не compile-time.
Re[4]: инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 16:35
Оценка:
ладно, сделаю в рантайме.
всем спасибо.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: инициализация массива байт в compile-time
От: igna Россия  
Дата: 19.03.13 16:39
Оценка:
Здравствуйте, niXman, Вы писали:

X>типа: static const char c[] = {a..., b...};


Если a и b тоже объявлены константными, то можно инициализировать только c, а a и b сделать ссылками на подмассивы c. Хотя без reinterpret_cast у меня это не получилось:

#include <iostream>
using namespace std;

static const char c[] = "0123456789";
static const char (&a)[5] = reinterpret_cast<const char (&)[5]>(c);
static const char (&b)[5] = reinterpret_cast<const char (&)[5]>(c[5]);

int main()
{
    cout << a[2] << ' ' << b[2]; // Prints 2 7
}


codepad
Re[4]: инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 16:45
Оценка:
Здравствуйте, igna, Вы писали:

I>static const char c[] = "0123456789";

I>static const char (&a)[5] = reinterpret_cast<const char (&)[5]>(c);
I>static const char (&b)[5] = reinterpret_cast<const char (&)[5]>(c[5]);

нет, все наоборот. есть а и б, нужно склеить и получить с.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: инициализация массива байт в compile-time
От: igna Россия  
Дата: 19.03.13 16:53
Оценка:
Здравствуйте, niXman, Вы писали:

X>нет, все наоборот. есть а и б, нужно склеить и получить с.


Ну если а и б ты не сам определяешь, тогда конечно нет.
Re[5]: инициализация массива байт в compile-time
От: Evgeny.Panasyuk Россия  
Дата: 19.03.13 17:26
Оценка: 15 (1)
Здравствуйте, niXman, Вы писали:

X>ладно, сделаю в рантайме.

X>всем спасибо.

если runtime, то с вариадиками можно сделать так:
{
   char left[]="left";
   char right[]="right";
   auto &&res=concatenate(left,"111","222",right);
   cout << res.data() << endl;
}

concatenate возвращает std::array
  full
#include <boost/range/algorithm/copy.hpp>
#include <boost/mpl/accumulate.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/int.hpp>
#include <boost/utility.hpp>
#include <iterator>
#include <iostream>
#include <ostream>
#include <cstddef>
#include <array>

using namespace boost;
using namespace std;


template<typename OutputIterator,typename Range>
OutputIterator copy_ranges(OutputIterator out,const Range &current)
{
   return copy(current,out);
}

template<typename BidirectionalIterator,typename Range,typename ...Ranges>
BidirectionalIterator copy_ranges(BidirectionalIterator out,const Range &current,const Ranges& ...ranges)
{
   return copy_ranges(prev(copy(current,out)),ranges...); // -1 for ignoring terminate null
}

template<typename T,size_t N>
using c_array_r = const T (&)[N];

template<typename Value,int ...sizes>
array
<
   Value,
   mpl::accumulate
   <
      mpl::vector_c<size_t,sizes...>, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2>
   >::type::value
>
concatenate(c_array_r<Value,sizes> ...arrays)
{
   array
   <
      Value,
      mpl::accumulate
      <
         mpl::vector_c<size_t,sizes...>, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2>
      >::type::value
   > result;
   copy_ranges(std::begin(result),arrays...);
   return result;
}

int main()
{
   char left[]="left";
   char right[]="right";
   auto &&res=concatenate(left,"111","222",right);
   cout << res.data() << endl;
}
Re[6]: инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 17:29
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>если runtime, то с вариадиками можно сделать так:

вариант, спасибо.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[7]: инициализация массива байт в compile-time
От: Evgeny.Panasyuk Россия  
Дата: 19.03.13 17:36
Оценка:
Кстати, result type внутри функции можно не копипастить, а сделать:
decltype(concatenate(arrays...)) result; // self return type
Re: инициализация массива байт в compile-time
От: Alexey F  
Дата: 19.03.13 18:14
Оценка: 52 (3)
Здравствуйте, niXman, Вы писали:

X>нужно, инициализировать массив c следующим образом(в псевдокоде): static const char c[] = a + '-' + b;

X>далее, переменная c будет использоваться для разбора, опять же в compile-time.

Можно, только синтаксис слегка корявый
Не совсем уверен, что код ниже не нарушает никакого спрятавшегося от меня особо коварного подпункта стандарта , но всё же;

constexpr, судя по разбору строк в compile-time, имеется.
Синтаксис будет вот такой:
// ...

// Если внести в функцию - no linkage error, как и ожидалось:
char constexpr a[] = "Hello, compile";
char constexpr b[] = "time world!";

int main() {
    std::cout
        << concatenateWithSplitter<'-', a, b>( a, b )
    << std::endl;
}

Либо такой:
// ... аналогично
char constexpr a[] = "Hello, compile";
char constexpr b[] = "time world!";

int main() {
    std::cout
        << ConcatenateWithSplitter<
            '-',
            a,
            decltype( strIndexes( a ) ),
            b,
            decltype( strIndexes( b ) )
        >::result
    << std::endl;
}

А весь код будет такой:
  Код
#include <iostream>
#include <cstddef>

namespace Aux {
   template<std::size_t... Indexes>
    struct IndexesContainer {};

    template<std::size_t I>
    struct IndexArg {};

    template<std::size_t N>
    struct IndexProvider {
        template<std::size_t... Indexes>
        static auto constexpr provide( IndexArg<Indexes>... args )
            -> decltype( IndexProvider<N - 1>::provide( IndexArg<N - 1>{}, args... ) ) {
            return IndexProvider<N - 1>::provide( IndexArg<N - 1>{}, args... );
        }
    };

    template<>
    struct IndexProvider<0> {
        template<std::size_t... Indexes>
        static constexpr IndexesContainer<Indexes...> provide( IndexArg<Indexes>... ) {
            return {};
        }
    };
}

template<std::size_t N>
auto constexpr indexes() -> decltype( Aux::IndexProvider<N>::provide() ) { return {}; }

template<
    char Symbol,
    char const* Left,
    class LeftIndexes,
    char const* Right,
    class RightIndexes
> struct ConcatenateWithSplitter;

template<
    char Symbol,
    char const* Left,
    std::size_t... LeftIndexes,
    char const* Right,
    std::size_t... RightIndexes
> struct ConcatenateWithSplitter<
    Symbol,
    Left,
    Aux::IndexesContainer<LeftIndexes...>,
    Right,
    Aux::IndexesContainer<RightIndexes...>
> {
    static char constexpr result[
        // Размер указан явно, чтобы clang не серчал:
        sizeof...( LeftIndexes ) + 1 + sizeof...( RightIndexes ) + 1
    ] = {
        Left[ LeftIndexes ]...,
        Symbol,
        Right[ RightIndexes ]...,
        0
    };
};

template<
    char Symbol,
    char const* Left,
    std::size_t... LeftIndexes,
    char const* Right,
    std::size_t... RightIndexes
> char constexpr ConcatenateWithSplitter<
    Symbol,
    Left,
    Aux::IndexesContainer<LeftIndexes...>,
    Right,
    Aux::IndexesContainer<RightIndexes...>
>::result[
    // Размер указан явно, чтобы clang не серчал:
    sizeof...( LeftIndexes ) + 1 + sizeof...( RightIndexes ) + 1
];

template<class T, std::size_t N>
auto constexpr strIndexes( T const ( & )[ N ] ) -> decltype( indexes<N - 1>() ) {
    return {};
}

template<
    char Symbol,
    char const* First,
    char const* Second,
    std::size_t FirstSize,
    std::size_t SecondSize
> auto constexpr concatenateWithSplitter(
    char const ( & )[ FirstSize ],
    char const ( & )[ SecondSize ]
) -> char const ( & )[ FirstSize - 1 + 1 + SecondSize - 1 + 1 ] {
    return ConcatenateWithSplitter<
        Symbol,
        First,
        decltype( indexes<FirstSize - 1>() ),
        Second,
        decltype( indexes<SecondSize - 1>() )
    >::result;
}


char constexpr a[] = "Hello, compile";
char constexpr b[] = "time world!";

int main() {
    std::cout
        << ConcatenateWithSplitter<
            '-',
            a,
            decltype( strIndexes( a ) ),
            b,
            decltype( strIndexes( b ) )
        >::result
    << std::endl;
    
    std::cout
        << concatenateWithSplitter<'-', a, b>( a, b )
    << std::endl;
}

Вывод здесь:

Hello, compile-time world!
Hello, compile-time world!


Проверял на liveworkspace с 4.7.2, 4.8.0 gcc и 3.2 clang.

P.S. Т.к. ф-ции — constexpr, полученный result можно использовать в параметрах шаблона:
template<char>
struct Tst {};
// ...
Tst<concatenateWithSplitter<'-', a, b>( a, b )[ 3 ]> tst;
Re[2]: инициализация массива байт в compile-time
От: Evgeny.Panasyuk Россия  
Дата: 19.03.13 18:34
Оценка:
Здравствуйте, Alexey F, Вы писали:

AF>char constexpr a[] = "Hello, compile";

AF>char constexpr b[] = "time world!";

Круто, то есть значения массива могут быть compile time:
constexpr char arr[] = "test";
enum{v1 = arr[0]};
enum{v2 = "test"[0]};


Точно, вспоминаю статью Using strings in C++ template metaprograms
Re[3]: инициализация массива байт в compile-time
От: Erop Россия  
Дата: 19.03.13 19:52
Оценка:
Здравствуйте, niXman, Вы писали:

X>a и b — обычные массивы байт. хотелось бы, чтоб так оно и осталось.


#define COMMA ", "
#define JUST_TRY_IT "это " "не" COMMA "то" COMMA "что " "тебе " "надо?"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: инициализация массива байт в compile-time
От: rg45 СССР  
Дата: 19.03.13 20:01
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Alexey F, Вы писали:


AF>>char constexpr a[] = "Hello, compile";

AF>>char constexpr b[] = "time world!";

EP>Круто, то есть значения массива могут быть compile time:

EP>
EP>constexpr char arr[] = "test";
EP>enum{v1 = arr[0]};
EP>enum{v2 = "test"[0]};
EP>

EP>
EP>Точно, вспоминаю статью Using strings in C++ template metaprograms


Во истину, век живи — век учись!

http://ideone.com/QlXZ8P

#include <iostream>

template<typename T, T const array[], int I>
struct Indexer
{
  static const T value = array[I];
};

constexpr int foo[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

enum Bar
{
  value1 = Indexer<int, foo, 1>::value, 
  value3 = Indexer<int, foo, 3>::value, 
  value7 = Indexer<int, foo, 7>::value, 
};

int main()
{
   std::cout << Bar::value3 << std::endl;
}


Жаль вот, что параметризовать шаблоны строковыми литералами по-прежнему нельзя
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 20:32
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>
#define COMMA ", "
E>#define JUST_TRY_IT "это " "не" COMMA "то" COMMA "что " "тебе " "надо?"

жуть какая %)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 20:33
Оценка:
Здравствуйте, rg45, Вы писали:

тоже вариант.

зы
я Вам дважды ЛС писал. Вы меня игнорируете, или что?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: инициализация массива байт в compile-time
От: rg45 СССР  
Дата: 19.03.13 20:45
Оценка:
Здравствуйте, niXman, Вы писали:

X>я Вам дважды ЛС писал. Вы меня игнорируете, или что?


Виноват... Расшифруй, плиз, что такое "ЛС" и куда писал: на сколько я могу видеть в своем профиле, это первое твое обращение ко мне за последний месяц.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: инициализация массива байт в compile-time
От: niXman Ниоткуда https://github.com/niXman
Дата: 19.03.13 20:49
Оценка:
Здравствуйте, rg45, Вы писали:

R>Виноват... Расшифруй, плиз, что такое "ЛС" и куда писал: на сколько я могу видеть в своем профиле, это первое твое обращение ко мне за последний месяц.

ЛС — Личные сообщения.
я писал дважды за последние три дня. сейчас напишу еще раз, вдруг таки недоставилось..
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.