баг компилятора cl 16.00 ???
От: jyuyjiyuijyu  
Дата: 05.07.14 03:14
Оценка:
Всем привет

этот код


#define WTF() []() { \
    \
    printf("%d\n", __LINE__); \
    \
    } ()

int _tmain(int argc, _TCHAR* argv[])
{
    WTF();

    return 0;
}


в Release собирается хорошо а в Debug выдаёт

error C2065: '__LINE__Var' : undeclared identifier


включил генерацию файла после препроцессора и вижу там полностью корректный код

[]() { printf("%d\n", 14); } ();


а собираться не хочет...

если подставить тело макроса в функцию

int _tmain(int argc, _TCHAR* argv[])
{
    []() {
        printf("%d\n", __LINE__); 
    } ();

    return 0;
}


то все прекрасно собирается...

кто глючит?

и если это баг подскажите как получить значение макроса __LINE__ в лямбде внутри макроса...

спасибо
Re: баг компилятора cl 16.00 ???
От: Кодт Россия  
Дата: 05.07.14 04:06
Оценка: 1 (1) +1
Здравствуйте, jyuyjiyuijyu, Вы писали:

Это не баг, а фича компилятора, в режиме edit-and-continue он раскрывает __LINE__ не как числовой литерал, а как целочисленную переменную плюс смещение.
Управляется опцией /Zi, по умолчанию включенной в дебаге.
Выбери вместо неё что-нибудь другое, и будет тебе счастье.
Свойства проекта, С++, отладочная информация — где-то там.
Перекуём баги на фичи!
Re[2]: баг компилятора cl 16.00 ???
От: jyuyjiyuijyu  
Дата: 05.07.14 04:21
Оценка:
Здравствуйте, Кодт, Вы писали:

ясно...

мне нужен именно __LINE__

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

чем его можно заменить ?

и почему вот такой код работает и никаких ошибок не выскакивает? правда число увеливается в 10 раз...
как бы так сделать чтобы число соответствовало __LINE__ ?

#define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)

#define BOOST_PP_CAT_I(a, b) a ## b

#define WTF() []() { \
    \
    printf("%d\n", BOOST_PP_CAT(__LINE__, 0)); \
    \
    } ()

int _tmain(int argc, _TCHAR* argv[])
{
    WTF();

    return 0;
}
Re[3]: баг компилятора cl 16.00 ???
От: jyuyjiyuijyu  
Дата: 05.07.14 05:02
Оценка:
нет, правильный вопрос звучит так

как на этапе препроцессинга получить рандомное число от 1 до 255 (для последующей конкатенации с именем переменной с помощью ##) ?
Re[4]: баг компилятора cl 16.00 ???
От: Кодт Россия  
Дата: 05.07.14 11:40
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>нет, правильный вопрос звучит так

J>как на этапе препроцессинга получить рандомное число от 1 до 255 (для последующей конкатенации с именем переменной с помощью ##) ?

Во-первых, отключить edit-n-continue, от него всё равно пользы немного.
Во-вторых, есть __COUNTER__
В-третьих, чтобы он трижды подставился одинаково, надо сделать так

http://ideone.com/iVoXnb

#define S(t)    S_(t)   // BOOST_PP_STR
#define S_(t)   #t
 
#define C(a,b)  C_(a,b) // BOOST_PP_CAT
#define C_(a,b) a##b
 
#define THREE(n)  printf("%s = %s = %d\n", S(C(var_,n)), S(n), n)
#define LINED()   THREE(__LINE__)
#define COUNTED() THREE(__COUNTER__)
 
int main() {
    LINED(); LINED();
    COUNTED(); COUNTED(); COUNTED();
    return 0;
}


А вот чтобы получить число строго в каком-то интервале, на стадии препроцессора, — тут извиняйте, штатных средств нет.
Могу лишь предложить сделать отдельный дополнительный препроцессор (элементарно: скрипт на перле или питоне), который будет работать или до, или после сишного препроцессора и выдавать лексемы — литералы от 1 до 255.

Если нужны не лексемы, то можно ведь и так поступить
#define UNIQUE_VAR_AND_VALUE_(n)  int C(var_,n) = (n) % 255 + 1;
#define UNIQUE_VAR_AND_VALUE()    UNIQUE_VAR_AND_VALUE_(__COUNTER__)

UNIQUE_VAR_AND_VALUE() // int var_254 = 254;
UNIQUE_VAR_AND_VALUE() // int var_255 = 255;
UNIQUE_VAR_AND_VALUE() // int var_256 =   1;


Либо, если это какая-то достаточно узкая задача с лексемами, можно припахать циклы из BOOST_PP. Они как раз до 255 умеют считать.
Поэтому расскажи, зачем тебе оно понадобилось.
Перекуём баги на фичи!
Re[4]: баг компилятора cl 16.00 ???
От: Vain Россия google.ru
Дата: 05.07.14 11:59
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>нет, правильный вопрос звучит так

J>как на этапе препроцессинга получить рандомное число от 1 до 255 (для последующей конкатенации с именем переменной с помощью ##) ?
// test.cpp : Defines the entry point for the console application.
//

#include <tchar.h>
#include <iostream>

extern size_t __declspec(thread) __LINE__Var = 0;

#define __LINE__Var __LINE__Var

#define WTF() { \
    \
    printf("%d\n", __LINE__); \
    \
    }

#define WTF2() []() { \
    \
    printf("%d\n", __LINE__); \
    \
    } ()

int _tmain(int argc, _TCHAR* argv[])
{
    WTF();

    WTF();


    WTF2(); // line 6 in main

    WTF2(); // line 8 in main

    WTF();

    WTF();


    WTF2(); // line 15 in main

    WTF2(); // line 17 in main

    return 0;
}

при включённом Edit and Continue вывод:
25
27
6
8
34
36
15
17

при выключённом Edit and Continue вывод:
25
27
30
32
34
36
39
41

Думаю в данном случае лямбды работают криво и их лучше не юзать для этого.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[5]: баг компилятора cl 16.00 ???
От: Кодт Россия  
Дата: 05.07.14 19:52
Оценка:
Здравствуйте, Vain, Вы писали:

V>
V>extern size_t __declspec(thread) __LINE__Var = 0;

V>#define __LINE__Var __LINE__Var
V>

Не понял, в чём здесь прикол? Зачем ты надуваешь компилятор?



V>Думаю в данном случае лямбды работают криво и их лучше не юзать для этого.

Думаю, что криво работают не сами лямбда, а именно edit-n-continue. Эта фича не соответствует стандарту и реализована непрозрачно и непредсказуемо.
Кстати, надо бы проверить, как она дружит не только с лямбдами, но и с обычными вложенными функциями:
#include <iostream>
using namespace std;
 
#define SHOW() (cout<<__LINE__<<endl)
 
int main() {
  SHOW(); // 7
 
  auto f = [ ]() { SHOW(); };
  auto g = [=]() { SHOW(); };
  auto h = [&]() { SHOW(); };
  struct I { void operator()() { SHOW(); } } i;
 
  SHOW(); // 14
  f(); g(); h(); i(); // 9 10 11 12
  SHOW(); // 16
  f(); g(); h(); i(); // 9 10 11 12
  SHOW(); // 18
}

http://ideone.com/Zf8nvz — gcc в качестве эталона

потому что понятно, что там творчески расставлены определения этой переменной, её присваивания и смещения относительно базы.
Перекуём баги на фичи!
Re[6]: баг компилятора cl 16.00 ???
От: Vain Россия google.ru
Дата: 05.07.14 20:38
Оценка:
Здравствуйте, Кодт, Вы писали:

V>>
V>>extern size_t __declspec(thread) __LINE__Var = 0;
V>>#define __LINE__Var __LINE__Var
V>>

К>Не понял, в чём здесь прикол?
Ну так компилятор ругается что не нашёл переменную, вот я её и подсунул. А дефайн здесь не нужен, это лоскуты от предыдущих тестов.

К>Зачем ты надуваешь компилятор?

Ему значит можно меня надумать, а мне его нет?

V>>Думаю в данном случае лямбды работают криво и их лучше не юзать для этого.

К>Думаю, что криво работают не сами лямбда, а именно edit-n-continue. Эта фича не соответствует стандарту и реализована непрозрачно и непредсказуемо.
Ну, лябды появились позже edit-n-continue, так что логичнее, что именно их плохо тестировали.

К>потому что понятно, что там творчески расставлены определения этой переменной, её присваивания и смещения относительно базы.

Так это понятно почему сделано. Если для разных лямбд результат будет одинаковый, то старые макросы генерирующие уникальность через __LINE__ могли бы сломаться в новом коде.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[5]: баг компилятора cl 16.00 ???
От: jyuyjiyuijyu  
Дата: 06.07.14 16:04
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Поэтому расскажи, зачем тебе оно понадобилось.


нужно было зашивать в имена переменных определяемых макросом рандомное число...
линкер генерирует мап файл, используя который утилита запускаемая в пост буилд находила
эти перменные и обрабатывала особым образом...


но решил совсем другим способом, как оказалось достаточно дать просто уникальные имена а рандомные
числа генерирует сама утилита при обработке, зашивая key для расшифровки вызывающему коду
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.