Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > [C++0x] функция генерация uid как constexpr


Автор: rudvil 29.4.2011, 15:24
Реально ли функцию std::size_t uid() сделать как constexpr, чтобы приведенный ниже код заработал?
http://liveworkspace.org/code/a64a5b6a70e0fd5c7226de52e9393491
Код
#include <cstddef>
#include <iostream>

std::size_t uid() {
  static std::size_t id = 0;
  return ++id;
}

struct foo {
  static const std::size_t id1 = uid();
  static const std::size_t id2 = uid();
};

int main() {
  std::cout << foo::id1 << std::endl;
  std::cout << foo::id2 << std::endl;
  return 0;
}


Цитата(output)
source.cpp:10:38: error: 'std::size_t uid()' is not 'constexpr'
source.cpp:11:38: error: 'std::size_t uid()' is not 'constexpr'

Build finished with errors


Про enum'ы знаю, их можно не предлагать.
Пока что смог вот так извратиться, но все время писать эти макросы жутко не удобно
http://liveworkspace.org/code/957f17038912deb402bcc6714c2fa5c8
Код
#include <cstddef>
#include <iostream>

#include <boost/preprocessor/slot/counter.hpp>

struct foo {
  static const std::size_t id1 = BOOST_PP_COUNTER;
#include BOOST_PP_UPDATE_COUNTER()
  static const std::size_t id2 = BOOST_PP_COUNTER;
};

int main() {
  std::cout << foo::id1 << std::endl;
  std::cout << foo::id2 << std::endl;
  std::cout << std::endl;
  return 0;
}


Цитата(output)
0
1

какие могут быть решения данной проблемы?

Автор: mes 29.4.2011, 17:10
Цитата(rudvil @  29.4.2011,  14:24 Найти цитируемый пост)
Реально ли функцию std::size_t uid() сделать как constexpr, чтобы приведенный ниже код заработал?

нет, constexpr функция не может иметь состояния.. 

Автор: rudvil 29.4.2011, 22:00
Цитата(mes @ 29.4.2011,  17:10)
Цитата(rudvil @  29.4.2011,  14:24 Найти цитируемый пост)
Реально ли функцию std::size_t uid() сделать как constexpr, чтобы приведенный ниже код заработал?

нет, constexpr функция не может иметь состояния..

Понятно, спасибо.

Автор: boostcoder 29.4.2011, 22:09
Цитата(rudvil @  29.4.2011,  15:24 Найти цитируемый пост)
все время писать эти макросы жутко не удобно

есть еще встроенный макрос __COUNTER__

Автор: rudvil 29.4.2011, 23:55
Цитата(boostcoder @ 29.4.2011,  22:09)
Цитата(rudvil @  29.4.2011,  15:24 Найти цитируемый пост)
все время писать эти макросы жутко не удобно

есть еще встроенный макрос __COUNTER__

Спасибо, кажется наилучшее решение.  smile 

Автор: mes 30.4.2011, 09:20
у решения с COUNTER недостаток в повторении значений в разных единицах трансляции... 
смотря для чего нужны id, и если к значению нет требований(в том числе и динамика), кроме его уникальности,  то можно использовать адресс переменной... хотя  подобный подход накладывает тоже много ограничений.. и обычно применяется для идентификатора типа.. 




Автор: boostcoder 30.4.2011, 16:12
Цитата(mes @  30.4.2011,  09:20 Найти цитируемый пост)
недостаток в повторении значений в разных единицах трансляции

если, к примеру, не нужны последовательные значения, то __COUNTER__ можно комбинировать с __LINE__

Автор: mes 30.4.2011, 16:18
Цитата(boostcoder @  30.4.2011,  15:12 Найти цитируемый пост)
то __COUNTER__ можно комбинировать с __LINE__ 

а разве это гарантирует уникальность ?

Добавлено через 1 минуту и 52 секунды
к тому же может привести к проблеме, когда из за добавления одной незначащий строчки, появиться неожидано непредвиденное поведение smile

Автор: boostcoder 30.4.2011, 16:21
Цитата(mes @  30.4.2011,  16:18 Найти цитируемый пост)
а разве это гарантирует уникальность ?

нет, естественно smile

Добавлено @ 16:24
Цитата(mes @  30.4.2011,  16:18 Найти цитируемый пост)
из за добавления одной незначащий строчки, появиться неожидано непредвиденное поведение

это да.

я когда-то пытался закодить что-то вроде этого.. мне нужен был компайл-тайм typeid. но только чтоб он не имена типов возвращал, а целые в качестве ID`ов. ну и забросил. вроде как на тот момент это мне казалось невозможным... была идея пропатчить компилятор smile

Автор: borisbn 2.5.2011, 12:54
Прошу прощения, что спрашиваю в чужой теме, но вопрос IMHO близкий...
А можно как-нибудь проверить в compile-time уникальность констант, но не через switch. Есть такой код
Код

template< unsigned long long ID >
struct MyStruct {
    static const unsigned long long id = ID;
...
};
typedef MyStruct< 0x123456789L > SomeStruct1;
typedef MyStruct< 0x123456789L > SomeStruct2; // вот тут хотелось бы получить ошибку

Если ТС будет против - создам отдельную тему.
Спасибо

Автор: boostcoder 2.5.2011, 13:10
borisbn, вроде как цели схожи: http://forum.vingrad.ru/forum/topic-319669.html

Добавлено через 1 минуту и 45 секунд
а вообще - нет, такое невозможно.
решение влоб - добавлять твои типы в некий mpl-контейнер с проверкой на предмет существования.

Автор: mes 2.5.2011, 14:37
Цитата(borisbn @  2.5.2011,  11:54 Найти цитируемый пост)
typedef MyStruct< 0x123456789L > SomeStruct1;
typedef MyStruct< 0x123456789L > SomeStruct2; // вот тут хотелось бы получить ошибку

это _вдвойне_ невозможно, так как typedef не создает новый тип  smile 

Автор: borisbn 2.5.2011, 15:57
Цитата(boostcoder @  2.5.2011,  13:10 Найти цитируемый пост)
а вообще - нет, такое невозможно.

Цитата(mes @  2.5.2011,  14:37 Найти цитируемый пост)
это _вдвойне_ невозможно

_вдвойне_ жаль :(

Цитата(boostcoder @  2.5.2011,  13:10 Найти цитируемый пост)
решение влоб - добавлять твои типы в некий mpl-контейнер с проверкой на предмет существования.

не очень понял (читай - вообще не понял), т.к. с mpl-контейнерами не работал. Можешь показать пример ? И ещё вопрос, __COUNTER__ исключительно gcc-шный, или в MSVC он тоже есть ?

mes, если не такой typedef, а какая-либо другая конструкция может дать compile-time ошибку при совпадении констант ?


Сейчас делаю совершенно дурацким способом - перед компиляцией сам парсю свой исохдник и проверяю константы на уникальность, но IMHO это не выход...

Автор: boostcoder 2.5.2011, 16:02
Цитата(borisbn @  2.5.2011,  15:57 Найти цитируемый пост)
И ещё вопрос, __COUNTER__ исключительно gcc-шный, или в MSVC он тоже есть ?

в MSVC тоже.

Цитата(borisbn @  2.5.2011,  15:57 Найти цитируемый пост)
Можешь показать пример ?

чичас smile

Автор: mes 2.5.2011, 16:20
Цитата(borisbn @  2.5.2011,  14:57 Найти цитируемый пост)
если не такой typedef, а какая-либо другая конструкция может дать compile-time ошибку при совпадении констант ?

в любом случае нужен список.. получить его можно 
либо при определении нового типа _наследоваться_ от предыдущего и сохранять полученный список типов внутри определяемого типа,  
либо отдельно от определений составить список всех нужных типов..
Ну а имея список типов легко проверить на уникальность,  вхождение в нужный диапазон и многое другое..

Автор: borisbn 2.5.2011, 20:42
Цитата(mes @  2.5.2011,  16:20 Найти цитируемый пост)
при определении нового типа _наследоваться_ от предыдущего и сохранять полученный список типов внутри определяемого типа

это как GoldFinch предлагал в теме, приведённой boostcoder ?

Код

template<int ID> stuct T;
template<> struct T<1> { typedef ... type; };
template<> struct T<2> { typedef ... T<1>::type ... type; };

?

Я, честно говоря, не очень понимаю, как это может помочь при проверке уникальности...

Автор: mes 2.5.2011, 22:37
Цитата(borisbn @  2.5.2011,  19:42 Найти цитируемый пост)
предлагал в теме,

грубо да

Цитата(borisbn @  2.5.2011,  19:42 Найти цитируемый пост)
, как это может помочь при проверке уникальности... 

зная все цепочку типов, вы может пробежаться по ней и проверить на уникальность.. 


Автор: borisbn 2.5.2011, 22:54
Цитата(mes @  2.5.2011,  22:37 Найти цитируемый пост)
вы может пробежаться по ней и проверить на уникальность.. 

Всё равно не понимаю. Как пробежаться ? Глазами ? В run-time ? Ладно, чтоб не мучать больше, последний вопрос/просьба - не могли бы Вы привести пример кода, на который бы ругался компилятор, в случае, если в качестве инстанциатора (слово-то какое) шаблона будут повторяющиеся константы. Спасибо.

Автор: boostcoder 3.5.2011, 03:42
Цитата(borisbn @  2.5.2011,  22:54 Найти цитируемый пост)
Как пробежаться ? ... В run-time ?

посмотри сюда: http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/refmanual_toc.html
там куча контейнеров и алгоритмов для работы с ними. как ты думаешь, это ран-тайм? smile 

Автор: mes 3.5.2011, 08:47
Цитата(borisbn @  2.5.2011,  21:54 Найти цитируемый пост)
Всё равно не понимаю. Как пробежаться ? Глазами ? В run-time ?  

ну списка типа в рантйме просто не существует, ну а если глазами, зачем его было составлять smile

Цитата(borisbn @  2.5.2011,  21:54 Найти цитируемый пост)
 не могли бы Вы привести пример кода,


Цитата

typedef vector<int,float,float,char,int,int,int,double> types;
typedef vector<int,float,char,int,double> expected;
typedef unique< types, is_same<_1,_2> >::type result;

BOOST_MPL_ASSERT(( equal< result,expected > ));

http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/unique.html

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)