Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 01.11.2020, 19:40   #61
Loksiin12
Форумчанин
 
Регистрация: 04.10.2020
Сообщений: 136
По умолчанию

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
Код:
template <typename Tuple, unsigned int I = Tuple::Size>
struct TupleForEach_
{
template <typename F>
static void run(Tuple & tpl, F f)
{
TupleForEach_<Tuple, (I - 1)>::run(tpl, f);
f(tpl.template get<(I - 1)>());
}
};
здесь нет рантайм-рекурсии, это рекурсия метапрограммная. Для рантайма будет каскадный вызов функций разных классов в дебаге. А в релизе будет без всего этого сразу обращение к нужной переменной - оптимизатор это сделает
Это обычная рекурсия которая работает по принципу "если иначе", ей можно управлять например:
Код:
template<typename Tuple,int Q = Tuple::Size>
struct TupleFor__{
template<typename F>
static void run(Tuple&tpl,F f,int*uk,int q){
cout<<"uk[q] "<<uk[q]<<" q-1 "<<Q-1<<endl;
if(/*1uk[q]*/1  ==Q-1){f(tpl.template get<(Q-1)>(),uk,q);cout<<"tpl.template get<(Q-1)>() "<<tpl.template get<(Q-1)>()<<endl;  return;}
TupleFor__<Tuple,(Q-1)>::run(tpl,f,uk,q);}};
Как вы видите это обычная функция сюда можно код вписывать, работает по итерациям как цикл фор. Так что о прямом попадании не может быть и речи. Эта штука делалась для имуляции цикла а не для попадания в индекс.
Loksiin12 вне форума Ответить с цитированием
Старый 01.11.2020, 19:42   #62
Loksiin12
Форумчанин
 
Регистрация: 04.10.2020
Сообщений: 136
По умолчанию

tpl.get<(0)>() здесь прямое попадание, нагрузки быть не должно как вы и писали эти метапрограммы сливаются и исключаются но управлять через переменную нельзя только константой в отличие от механизма выше. Но выше рекурсии потому что даже индексы выводятся.
Loksiin12 вне форума Ответить с цитированием
Старый 02.11.2020, 10:19   #63
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

Loksiin12, я выше скидывал ссылку https://godbolt.org/ , вбей туда код из первого поста.
Выбери какой-нибудь C++ компилятор (например, x86-64 clang ) , справа в окошке введи опции компилятора

сначала без оптимизации
Код:
-std=c++17 -O0
посмотри, что будет в ассемблерном листинге функции main. Будет просто вызов функции

затем добавляем оптимизацию
Код:
-std=c++17 -O1
тут магии не произошло

затем
Код:
-std=c++17 -O2
тут уже оптимизатор постарался

есть ещё -O3 и -O4
Алексей1153 вне форума Ответить с цитированием
Старый 02.11.2020, 10:22   #64
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

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

Код:
int main()
{
    Tuple<int, char, double> tpl;
    
    tpl.get<0>() = 1;
    tpl.get<1>() = 'a';
    tpl.get<2>() = 3.14;

    std::cout<< tpl.get<0>();
    std::cout<< tpl.get<1>();
    std::cout<< tpl.get<2>();
    
    TupleForEeach(tpl, CoutPrinter());
}
Алексей1153 вне форума Ответить с цитированием
Старый 02.11.2020, 17:27   #65
Loksiin12
Форумчанин
 
Регистрация: 04.10.2020
Сообщений: 136
По умолчанию

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
чтобы оптимизатор тупо не выкидывал пустой код, можно добавить вывод в консоль
Вы хотите сказать что эта функция
Код:
template<typename Tuple,int Q = Tuple::Size>
struct TupleFor__{
template<typename F>
static void run(Tuple&tpl,F f,int*uk,int q){
cout<<"uk[q] "<<uk[q]<<" q-1 "<<Q-1<<endl;
if(/*1uk[q]*/1  ==Q-1){f(tpl.template get<(Q-1)>(),uk,q);cout<<"tpl.template get<(Q-1)>() "<<tpl.template get<(Q-1)>()<<endl;  return;}
TupleFor__<Tuple,(Q-1)>::run(tpl,f,uk,q);}};
Равносильна прямому попаданию в get<(...)>(), я так запускал смотрел там и индексы крутятся меняется, можно сказать что эта функция цикл а значит это уже не прямое попадание это вызов функции
Loksiin12 вне форума Ответить с цитированием
Старый 03.11.2020, 07:31   #66
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

Loksiin12, я не знаю, что там за попадания в функции и кручения индексов, в C++ нет таких терминов. В программе обычно всё чётко заранее заложено, если нет неопределённого поведения. В метапрограмме заранее заложена генерация классов, функций и констант

то, что у тебя там всё выводится в консоль - так это ты сам побочных эффектов наплодил
Код:
    cout<<"uk[q] "<<uk[q]<<" q-1 "<<Q-1<<endl;
раз это приходится делать, компилятор не имеет права оптимизировать так, чтобы эта строка пропала

а вот так
Код:
template<typename Tuple,int Q = Tuple::Size>
struct TupleFor__
{
  template<typename F>
  static void run(Tuple& tpl, F f, int* uk, int q)
  {
    if(1==Q-1)
    {
       f(tpl.template get<(Q-1)>(),uk,q);
       return;
    }

    TupleFor__<Tuple,(Q-1)>::run(tpl,f,uk,q);}
};
допустим, у нас есть переменная типа Tuple (в котором константа Tuple::Size равна 3)
имеется шаблон
Код:
template <typename Tuple, unsigned int I = Tuple::Size>
struct TupleForEach_ 
{
    template <typename F>
    static void run(Tuple & tpl, F f) 
    {
        TupleForEach_<Tuple, (I - 1)>::run(tpl, f);
        f(tpl.template get<(I - 1)>());
    }
};
 
template <typename Tuple>
struct TupleForEach_<Tuple, 0> 
{
    template <typename F>
    static void run(Tuple & tpl, F f) { }
};
 
template <typename Tuple, typename F>
void TupleForEeach(Tuple & x, F f) 
{
    TupleForEach_<Tuple>::run(x, f);
}
компилятор делает подстановку (для наглядности сделаю алиас Tuple_3, Tuple_2, Tuple_1 для типов с соответствующим размером)
Обрати внимание, что более ранние подстановки - ниже по коду. То есть, когда компилятору нужно рекурсивно инстанцировать шаблон, он создаёт его код ВЫШЕ текущей точки подстановки, чтобы, согласно правилам C++ было возможно использовать получившийся класс

Код:
//подстановка №5
//template <typename Tuple_0>
struct TupleForEach_<Tuple_0, 0> 
{
    template <typename F>
    static void run(Tuple_0 & tpl, F f)
    {
    }
};

//подстановка №4
//template <Tuple_1, unsigned int I = 1>
struct TupleForEach_ 
{
    template <typename F>
    static void run(Tuple_1 & tpl, F f) 
    {
        TupleForEach_<Tuple_0, 0)>::run(tpl, f);
        f(tpl.template get<0>());
    }
};

//подстановка №3
//template <Tuple_2, unsigned int I = 2>
struct TupleForEach_ 
{
    template <typename F>
    static void run(Tuple_2 & tpl, F f) 
    {
        TupleForEach_<Tuple_1, 1)>::run(tpl, f);
        f(tpl.template get<1>());
    }
};

//подстановка №2
//template <Tuple_3, unsigned int I = 3>
struct TupleForEach_ 
{
    template <typename F>
    static void run(Tuple_3 & tpl, F f) 
    {
        TupleForEach_<Tuple_2, 2)>::run(tpl, f);
        f(tpl.template get<2>());
    }
};

//подстановка №1
//template <typename Tuple_3, typename F>
void TupleForEeach(Tuple_3 & x, F f) 
{
    TupleForEach_<Tuple_3>::run(x, f);
}
функции статические, поэтому это всё эквивалентно вот такому каскаду функций

Код:
void run(Tuple_0 & tpl, F f)
{
}

void run(Tuple_1 & tpl, F f) 
{
    run(tpl, f);
    f(tpl.template get<0>());
}

void run(Tuple_2 & tpl, F f) 
{
    run(tpl, f);
    f(tpl.template get<1>());
}

void run(Tuple_3 & tpl, F f) 
{
    run(tpl, f);
    f(tpl.template get<2>());
}

void TupleForEeach(Tuple_3 & x, F f) 
{
    run(x, f);
}
оптимизатор их заинлайнит скорее всего, и получится просто один вызов
Алексей1153 вне форума Ответить с цитированием
Старый 03.11.2020, 14:37   #67
Loksiin12
Форумчанин
 
Регистрация: 04.10.2020
Сообщений: 136
По умолчанию

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
функции статические, поэтому это всё эквивалентно вот такому каскаду функций
из примера ниже можно сделать вывод что это перегрузка и попадание действительно прямое, но возникает вопрос что происходит когда я дописал туда строку
Код:
cout<<"uk[q] "<<uk[q]<<" q-1 "<<Q-1<<endl;
, то создаётся впечатление что оно крутит их постепенно сначала рассматривается индекс 0, а потом постепенно проходятся и остальные элементы пока не сработает условие if(1==Q-1)..., разве программа может себя вести как циклическая функция и как прямое попадание. Я так понимаю что прямое попадание это cout<<tpl.get<1>(), а рассматриваемый нами пример походит на цикл, пусть он и рекурсивный но это цикл. Эту функцию так и закумментировали Имуляция перебора в цикле.
Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
оптимизатор их заинлайнит скорее всего, и получится просто один вызов
есть такой параметр называется inline, возникает вопрос зачем его ставить в ручную если оптимизатор сам это сделает в возможных и целесообразных случаях? есть и другие соглашения вызовов но они тоже сомнительны например fatscal, анологичный вопрос компилятор сам положит нужные элементы в регистры которые чаще используются зачем писать лишний код.

Последний раз редактировалось Loksiin12; 03.11.2020 в 14:41.
Loksiin12 вне форума Ответить с цитированием
Старый 03.11.2020, 14:42   #68
Loksiin12
Форумчанин
 
Регистрация: 04.10.2020
Сообщений: 136
По умолчанию

Может не все компиляторы оптимизируют код или просто настроены по разному.
Loksiin12 вне форума Ответить с цитированием
Старый 04.11.2020, 08:34   #69
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

Цитата:
Сообщение от Loksiin12 Посмотреть сообщение
что происходит когда я дописал туда строку
ввод/вывод оптимизатор не имеет права выкинуть, потому что это они вызывают побочные эффекты. А вот такой локальный вызов функции, которая ничего не меняет, оптимизатор может просто выкинуть или встроить по месту вызова, если там ничего сложного не происходит

Цитата:
Сообщение от Loksiin12 Посмотреть сообщение
inline
в ранних стандартах C++ это была подсказка компилятору, что функцию неплохо бы заинлайнить (но он мог делать это на своё усмотрение). В новых стандартах inline в глобальной области видимости означает, что объект (функция или переменная) будет всего один, даже если он из заголовочника попал в несколько единиц трансляции
Алексей1153 вне форума Ответить с цитированием
Старый 04.11.2020, 09:14   #70
Loksiin12
Форумчанин
 
Регистрация: 04.10.2020
Сообщений: 136
По умолчанию

Цитата:
Сообщение от Алексей1153 Посмотреть сообщение
в ранних стандартах C++ это была подсказка компилятору, что функцию неплохо бы заинлайнить (но он мог делать это на своё усмотрение).
98ой стандарт по умолчанию не будет её инлайнить, или скорее всего будет, довольно абстрактное описание вы дали этому событию. Значит целесообразно ставить этот спецификатор.
Loksiin12 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Разобраться с кодом Boris2 Помощь студентам 1 15.07.2013 15:58
С++ разобраться с кодом marina12 Помощь студентам 2 21.05.2013 23:22
разобраться с кодом iris_ka Помощь студентам 0 16.05.2012 17:19
Разобраться с кодом. Vlero PHP 2 20.01.2011 12:46
проблемка с кодом, результат получается немного не такой как надо hen Помощь студентам 3 24.04.2009 15:11