Re: статическая компиляция
От: rg45 СССР  
Дата: 22.05.08 11:40
Оценка: 2 (1)
Здравствуйте, dalen, Вы писали:

D>Хочу добиться статического преобразования enum в порядковый номер элемента в этом самом enum.


Во-первых, согласен с cencio, что перечисления — неупорядоченные множества и говорить о порядковом номере элемента бессмысленно;
Во-вторых, как следствие из "во-первых", привязку значений к порядковым номерам можно только определить самому;
В-третьих, а как быть с повторяющимися значениями в перечислении?
В-четвертых, вариант решения, с учетом сказанного выше:
template<int> struct XMap;
#define XMAP_ADD(i, x) template<> struct XMap<(x)> { enum { index = (i) }; };
#define XMAP_INDEX_OF(x) (XMap<(x)>::index)

enum X 
{
  EL1 = 134,
  EL2 = 10,
  EL3 = 487
};

XMAP_ADD(1, EL1)
XMAP_ADD(2, EL2)
XMAP_ADD(3, EL3)

int assert
[
  XMAP_INDEX_OF(EL1) == 1 && 
  XMAP_INDEX_OF(EL2) == 2 && 
  XMAP_INDEX_OF(EL3) == 3 
];

Ну и, наконец, а зачем все это, если не секрет, где это может оказаться полезным?
--
Справедливость выше закона. А человечность выше справедливости.
Re: статическая компиляция
От: Masloboev Россия  
Дата: 22.05.08 08:33
Оценка: 1 (1)
возможно стоит специализировать шаблон крайними значениями:

template <Foo::X x> 
struct X2IT<x, -1>
    { 
        enum {value = -1};
    };


в таком случае компилятор будет развертывать до крайнего значения и остановится.
Re: статическая компиляция
От: cencio Украина http://ua-coder.blogspot.com
Дата: 22.05.08 10:26
Оценка: +1
Здравствуйте, dalen, Вы писали:

D>Добрый день!


D>Хочу добиться статического преобразования enum в порядковый номер элемента в этом самом enum.

про две ошибки в коде уже написали,
но есть вопрос — enum это просто асоциация целой константы с именем, грубо говоря
твой енум заменяет несколько макросов

#define EL1 134
#define EL2 10
#define EL3 487

и убирает проблемы свяаные с ними проблемы
А вот что означает "порядковый номер элемента в энуме"? какая-то странная концепция, enum это не упорядоченная структура, просто имя для целочисленной константы, что тогда понимать под номером элемента?
статическая компиляция
От: dalen  
Дата: 22.05.08 08:14
Оценка:
Добрый день!

Хочу добиться статического преобразования enum в порядковый номер элемента в этом самом enum. Компилятор вылетает по ошибке:

class Foo {
public:
    enum X {
        EL1 = 134,
        EL2 = 10,
        EL3 = 487
    };
    const static Foo::X TRX[3];
};

const Foo::X Foo::TRX[3] = {Foo::EL1,Foo::EL2,Foo::EL3};

void func(Foo::X);
inline Foo::X I2X(int i) { return Foo::TRX[i]; }
template <Foo::X x, int i> struct X2IT{ enum {value = (i == -1) ? -1 : ((x == I2X(i)) ? i : X2IT<x,i-1>::value)}; };
template <Foo::X x> struct X2I { enum {value = X2IT<x,sizeof(Foo::TRX)/sizeof(Foo::X)-1>::value};};

int _tmain(int argc, _TCHAR* argv[])
{
    cout << X2I<Foo::EL3>::value; // здесь ошибка
    return 0;
}


ошибка:

1>.\SS.cpp(27) : fatal error C1001: An internal error has occurred in the compiler.
1>(compiler file 'msc1.cpp', line 1392)
1> To work around this problem, try simplifying or changing the program near the locations listed above.
1>Please choose the Technical Support command on the Visual C++ 
1> Help menu, or open the Technical Support help file for more information
1>        .\SS.cpp(27) : see reference to class template instantiation 'X2IT<x,i>' being compiled
1>        with
1>        [
1>            x=EL3,
1>            i=-492
1>        ]
1>        .\SS.cpp(27) : see reference to class template instantiation 'X2IT<x,i>' being compiled
1>        with
1>        [
1>            x=EL3,
1>            i=-491
1>        ]
1>   .... и так далее


т.е. компилятор пытается раскрыть всё глубже и глубже template. Как его остановить ?

Павел
Re: статическая компиляция
От: remark Россия http://www.1024cores.net/
Дата: 22.05.08 08:32
Оценка:
Здравствуйте, dalen, Вы писали:

D>т.е. компилятор пытается раскрыть всё глубже и глубже template. Как его остановить ?


Добавь специализацию шаблона:
template <Foo::X x, int i> struct X2IT<x, -1> { enum {value = -1}; };



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: статическая компиляция
От: dalen  
Дата: 22.05.08 09:30
Оценка:
Здравствуйте, Masloboev, Вы писали:

M>в таком случае компилятор будет развертывать до крайнего значения и остановится.


Теперь он говорит ".\SS.cpp(30) : error C2057: expected constant expression"

Павел
Re: статическая компиляция
От: Erop Россия  
Дата: 22.05.08 09:52
Оценка:
Здравствуйте, dalen, Вы писали:


D>
D>const Foo::X Foo::TRX[3] = {Foo::EL1,Foo::EL2,Foo::EL3};
D>


А как ты собираешься читать значения из массива в CT?

Если уж тебе надо как-то забомбить итерацию списка в CT, то делай его как-то на списках типов, напрмиер...

Хотя я не понимаю в чём практический смысл этих упражнений в остроумии? Не пояснишь?

Я бы, например, (если бы мне таки это надо зачем-то было) так сделал:
template<int i> struct int_value { enum { value = i }; };
struct my_enum {
    enum Type {
        V1 = 10,
        V2 = 28, 
        V3 = -3, 
    };

    template<Type t> struct order;
    template<> struct order<V1> : int_value<1> {};
    template<> struct order<V2> : int_value<2> {};
    template<> struct order<V3> : int_value<3> {};
};


А скорее всего, постарался бы обойтись вообще только трансляцией в RT.

Например так.
1) Завести enum без указания констант
2) Завести функцию, осуществляющую трансляцию в константы и обратно, например по статической таблице...
3) Пользоваться и радоваться...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: статическая компиляция
От: dalen  
Дата: 22.05.08 10:28
Оценка:
Здравствуйте, Erop, Вы писали:

E>Хотя я не понимаю в чём практический смысл этих упражнений в остроумии? Не пояснишь?

E>А скорее всего, постарался бы обойтись вообще только трансляцией в RT.
E>Например так.
E>1) Завести enum без указания констант
E>2) Завести функцию, осуществляющую трансляцию в константы и обратно, например по статической таблице...
E>3) Пользоваться и радоваться...

Я сделал по второму методу. Проблема в том, что а) в enum нужны константы, б) нужно связать конкретную константу и некоторые результаты.
Понятно, что можно написать map<Foo::X, pair<double,bool>> но тогда получится лишний overhead на поиск по map. Т.е. смысл такой — есть числовые константы (от 0 до 599), которые не поменять — внешняя библиотека, которая по этим константам считает некоторые данные. Нужно а) рассчитать, б) многократно пробегать по рассчитанным значениям в определенном порядке (не по возрастанию, к сожалению). Соответственно, функции трансляции int -> enum -> int вызываются многократно, при этом 90% вызовов — фактически, указание верхней границы индекса для цикла for(int i = 0; i != X2I(Foo::EL3); i++).
Вот и думаю, можно ли их статически закомпилировать?..

Павел
Re[3]: статическая компиляция
От: alsemm Россия  
Дата: 22.05.08 11:25
Оценка:
...
D>Я сделал по второму методу. Проблема в том, что а) в enum нужны константы, б) нужно связать конкретную константу и некоторые результаты.
D>Понятно, что можно написать map<Foo::X, pair<double,bool>> но тогда получится лишний overhead на поиск по map. Т.е. смысл такой — есть числовые константы (от 0 до 599), которые не поменять — внешняя библиотека, которая по этим константам считает некоторые данные. Нужно а) рассчитать, б) многократно пробегать по рассчитанным значениям в определенном порядке (не по возрастанию, к сожалению). Соответственно, функции трансляции int -> enum -> int вызываются многократно, при этом 90% вызовов — фактически, указание верхней границы индекса для цикла for(int i = 0; i != X2I(Foo::EL3); i++).
D>Вот и думаю, можно ли их статически закомпилировать?..
Есть решние на половину статическое, наполовину RT. Как-то так:
завести два массива:
int enum2idx[600]; // enum -> idx
int idx2enum[600]; // int -> enum


и функции, кот. массивы используют:
inline int X2I(Foox::X v)
{
    return enum2idx[v];
}

inline Foox::X I2X(int v)
{
    return (Foox::X)idx2enum[v];
}


остается только проблема заполнения массивов. Решается написанием простецкого кодогенератора, например используя sed. На вход он получает исходник, с объявлением
class Foo {
public:
    enum X {
        EL1 = 134,
        EL2 = 10,
        EL3 = 487
    };  
};

на выходе что-то в этом духе
void initMaps()
{
    enum2idx[EL1] = 0;
    idx2enum[0] = EL1;
    enum2idx[EL2] = 1;
    idx2enum[1] = EL2;
...
    enum2idx[EL600] = 599;
    idx2enum[599] = EL600;
}


sed скрипт для initMaps могу вам за бесплатно написать/отладить за 30минут, если дадите рабочий хедер с объявлением Foo::X.

Алексей
Re[3]: статическая компиляция
От: Erop Россия  
Дата: 22.05.08 12:55
Оценка:
Здравствуйте, dalen, Вы писали:

D>Вот и думаю, можно ли их статически закомпилировать?..


Ну я бы завёл такой примерно класс:
struct MyEnum {
    enum Type {
        VBegin = 0, 
        VEnd = 3
    };

    static LibEnum GetValue( Type t ) { assert( VBegin <= t && t < VEnd ); return values[t]; }
private:
    static const LibEnum values[VEnd];
};
//  В *.cpp
const LibEnum MyEnum::values[VEnd] = { LibEnum_V1, LibEnum_V2, LibEnum_V3 };
И в своём коде всегда бы работал с MyEnum::Type (или int), MyEnum::VStart, MyEnum::VEnd

Если очень надо, можно ещё и искалку MyEnum по LibEnum написать. Типа std::find заюзать, или цикл написать.
Тогда ещё можно будет и константы типа MyEnum::Type описать. Короче как-то так получается:
//    Библиотечный хедер
enum LibEnum {
    Ups = 100, 
    Oh = 204, 
    Waw = -176
};

//    твой хедер
struct MyEnum {
    enum Type { VBegin = 0, VEnd = 3 };
    
    static const Type Ups;
    static const Type Oh;
    static const Type Waw;

    static LibEnum GetValue( int t ) { assert( VBegin <= t && t < VEnd ); return values[t]; }
    static Type FindValue( LibEnum e ) 
    { 
        for( int i = VBegin; i < VEnd; i++ )
            if( values[i] == e )
                return static_cast<Type>( i );
        return VEnd;
    }

private:
    static const LibEnum values[VEnd];
};
//  твой cpp
#define DEC_ENTRY( name ) const MyEnum::Type MyEnum::name = MyEnum::FindValue( ::name );
DEC_ENTRY( Ups )
DEC_ENTRY( Oh )
DEC_ENTRY( Waw )
const LibEnum MyEnum::values[MyEnum::VEnd] = { ::Ups, ::Oh, ::Waw };
//    Где-то в коде
void foo()
{
    const MyEnum::Type skipIt = MyEnum::Waw;
    for( int i = MyEnum::VBegin; i < MyEnum::VEnd; i++ ) {
        if( i == skipIt )
            continue;
        CallLibrary( MyEnum::GetValue( i ) );    //    Собственно вызов сторонней функции...
    }
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.