2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 20:42 


11/08/18
62
Добрый день,

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

код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <stdio.h>

#include <functional>

template <typename T> inline void SortFunc(int ResPlace, int N, T *p, T *buf, int (*CMP)(T &, T &)) // сортирует так, чтобы получилось [0]>=[1]>=...,>=[N-1]
{ int i, j1, j2, k;
  T *pr, *p1, *p2;

  if(ResPlace)
  { if(N==2)
    { if(CMP(p[1],p[0])) { buf[0]=p[1]; buf[1]=p[0]; }
      else { buf[0]=p[0]; buf[1]=p[1]; }
      return;
    } else if(N==1)
    { buf[0]=p[0];
      return;
    } else
    { k=N/2;
      SortFunc(0, k, p, buf, CMP);
      SortFunc(0, N-k, p+k, buf+k, CMP);
      pr=buf;
      p1=p;
      p2=p+k;
    }
  } else
  { if(N==2)
    { if(CMP(p[1],p[0])) { buf[0]=p[0]; p[0]=p[1]; p[1]=buf[0]; }
      return;
    } else if(N==1) return;
    else
    { k=N/2;
      SortFunc(1, k, p, buf, CMP);
      SortFunc(1, N-k, p+k, buf+k, CMP);
      pr=p;
      p1=buf;
      p2=buf+k;
    }
  }
  j1=j2=i=0;
  while(1)
  { if(CMP(p1[j1],p2[j2]))
    { pr[i++]=p1[j1++];
      if(j1==k) { while(i<N) pr[i++]=p2[j2++]; return; }
    } else
    { pr[i++]=p2[j2++];
      if(j2==N-k)
      { while(i<N) pr[i++]=p1[j1++]; return; }
    }
  }
}


int FuncM(int &t1, int &t2) { return (t1<t2)?1:0; }
int FuncG(int &t1, int &t2) { return (t1>t2)?1:0; }


template <typename T> inline void SortLow(int N, T *Data, T *Buf) // сортирует так, чтобы получилось [0]<=[1]<=...,<=[N-1]
{ auto Func1 { [] (T &t1, T &t2) -> int { return (t1>t2)?1:0; }};
  std::function<int(T&,T&)> Func2 = [&] (T &t1, T &t2) -> int { return (t1>t2)?1:0; };
  SortFunc(0, N, Data, Buf, FuncG); // здесь все работает
//  SortFunc(0, N, Data, Buf, &Func1); // но хочется, чтобы работало с ламбдой, так как не хочется описывать функцию глобально
//  SortFunc(0, N, Data, Buf, Func2); // во всех остальных вариациях тоже не получается...
//  SortFunc(0, N, Data, Buf, &Func1); // и здесь
//  SortFunc(0, N, Data, Buf, &Func2); // и здесь
//  SortFunc(0, N, Data, Buf, [&] (T &t1, T &t2) { return (t1>t2)?1:0; }); // и даже здесь
}

template <typename T> inline void SortHigh(int N, T *Data, T *Buf) // сортирует так, чтобы получилось [0]>=[1]>=...,>=[N-1]
{ SortFunc(0, N, Data, Buf, FuncM); // здесь все работает
}

int main()
{ int a[] = {1, 2, 5, 8, 8, 3, 11};
  int Buf[7];

  SortLow(sizeof(a)/sizeof(a[0]), a, Buf);
  for(int i=0; i<7; i++) printf("%d ", a[i]);
  printf("\n");
  SortHigh(sizeof(a)/sizeof(a[0]), a, Buf);
  for(int i=0; i<7; i++) printf("%d ", a[i]);
  printf("\n");
  return 0;
}
 


Помогите, пожалуйста, советом, что я делаю не так, и как подставить лямбду в темплейт выше.

Спасибо!

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 20:50 
Заслуженный участник
Аватара пользователя


06/10/08
6391
Используется синтаксис C++
 template <typename T> inline void SortFunc(int ResPlace, int N, T *p, T *buf, std::function<int(T&, T&)> CMP)

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 21:43 


11/08/18
62
Спасибо большое, Xaositect !

Xaositect в сообщении #1501757 писал(а):
Используется синтаксис C++
 template <typename T> inline void SortFunc(int ResPlace, int N, T *p, T *buf, std::function<int(T&, T&)> CMP)


Да, до такого я не додумался, ибо хотелось и обычно описанные функции туда же подставлять, а так их всех через std::function объявлять придется.

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 21:45 
Заслуженный участник
Аватара пользователя


06/10/08
6391
ilghiz в сообщении #1501766 писал(а):
Да, до такого я не додумался, ибо хотелось и обычно описанные функции туда же подставлять, а так их всех через std::function объявлять придется.
Нет, можно вызывать и с обычной функцией, там преобразование пройдет (у std::function есть нужный конструктор).

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 21:55 


11/08/18
62
Xaositect в сообщении #1501767 писал(а):
Нет, можно вызывать и с обычной функцией, там преобразование пройдет (у std::function есть нужный конструктор).


Спасибо за ответ! У меня правда не работает:

код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <stdio.h>
#include <functional>

template <typename T> inline void SortFunc(int ResPlace, int N, T *p, T *buf, std::function<int(T&, T&)> CMP)
{ int i, j1, j2, k;
  T *pr, *p1, *p2;

  if(ResPlace)
  { if(N==2)
    { if(CMP(p[1],p[0])) { buf[0]=p[1]; buf[1]=p[0]; }
      else { buf[0]=p[0]; buf[1]=p[1]; }
      return;
    } else if(N==1)
    { buf[0]=p[0];
      return;
    } else
    { k=N/2;
      SortFunc(0, k, p, buf, CMP);
      SortFunc(0, N-k, p+k, buf+k, CMP);
      pr=buf;
      p1=p;
      p2=p+k;
    }
  } else
  { if(N==2)
    { if(CMP(p[1],p[0])) { buf[0]=p[0]; p[0]=p[1]; p[1]=buf[0]; }
      return;
    } else if(N==1) return;
    else
    { k=N/2;
      SortFunc(1, k, p, buf, CMP);
      SortFunc(1, N-k, p+k, buf+k, CMP);
      pr=p;
      p1=buf;
      p2=buf+k;
    }
  }
  j1=j2=i=0;
  while(1)
  { if(CMP(p1[j1],p2[j2]))
    { pr[i++]=p1[j1++];
      if(j1==k) { while(i<N) pr[i++]=p2[j2++]; return; }
    } else
    { pr[i++]=p2[j2++];
      if(j2==N-k)
      { while(i<N) pr[i++]=p1[j1++]; return; }
    }
  }
}


int FuncM(int &t1, int &t2) { return (t1<t2)?1:0; }
int FuncG(int &t1, int &t2) { return (t1>t2)?1:0; }


template <typename T> inline void SortLow(int N, T *Data, T *Buf) // сортирует так, чтобы получилось [0]<=[1]<=...,<=[N-1]
{ //  auto Func1 { [] (T &t1, T &t2) -> int { return (t1>t2)?1:0; }};
  std::function<int(T&,T&)> Func = [&] (T &t1, T &t2) -> int { return (t1>t2)?1:0; };
//  SortFunc(0, N, Data, Buf, &Func1);
//  SortFunc(0, N, Data, Buf, Func2);
//  SortFunc(0, N, Data, Buf, &Func1);
  SortFunc(0, N, Data, Buf, Func);
//  SortFunc(0, N, Data, Buf, [&] (T &t1, T &t2) { return (t1>t2)?1:0; });
  SortFunc(0, N, Data, Buf, FuncG);
}

template <typename T> inline void SortHigh(int N, T *Data, T *Buf) // сортирует так, чтобы получилось [0]>=[1]>=...,>=[N-1]
{ // auto Func = [&] (T &t1, T &t2) -> int { return (t1>t2)?1:0; };
  std::function<int(T&,T&)> Func = [&] (T &t1, T &t2) -> int { return (t1<t2)?1:0; };
  SortFunc(0, N, Data, Buf, Func);
  SortFunc(0, N, Data, Buf, FuncM);
}

int main()
{ int a[] = {1, 2, 5, 8, 8, 3, 11};
  int Buf[7];

  SortLow(sizeof(a)/sizeof(a[0]), a, Buf);
  for(int i=0; i<7; i++) printf("%d ", a[i]);
  printf("\n");
  SortHigh(sizeof(a)/sizeof(a[0]), a, Buf);
  for(int i=0; i<7; i++) printf("%d ", a[i]);
  printf("\n");
  return 0;
}
 


вылетая на компиляции:

Код:
$ g++-10 -std=c++17 -Wall -O3 sort.cpp
sort.cpp: In instantiation of ‘void SortLow(int, T*, T*) [with T = int]’:
sort.cpp:88:41:   required from here
sort.cpp:74:11: error: no matching function for call to ‘SortFunc(int, int&, int*&, int*&, int (&)(int&, int&))’
   74 |   SortFunc(0, N, Data, Buf, FuncG);
      |   ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
sort.cpp:14:35: note: candidate: ‘template<class T> void SortFunc(int, int, T*, T*, std::function<int(T&, T&)>)’
   14 | template <typename T> inline void SortFunc(int ResPlace, int N, T *p, T *buf, std::function<int(T&, T&)> CMP)
      |                                   ^~~~~~~~
sort.cpp:14:35: note:   template argument deduction/substitution failed:
sort.cpp:74:11: note:   mismatched types ‘std::function<int(T&, T&)>’ and ‘int (*)(int&, int&)’
   74 |   SortFunc(0, N, Data, Buf, FuncG);
      |   ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
sort.cpp: In instantiation of ‘void SortHigh(int, T*, T*) [with T = int]’:
sort.cpp:91:42:   required from here
sort.cpp:81:11: error: no matching function for call to ‘SortFunc(int, int&, int*&, int*&, int (&)(int&, int&))’
   81 |   SortFunc(0, N, Data, Buf, FuncM);
      |   ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
sort.cpp:14:35: note: candidate: ‘template<class T> void SortFunc(int, int, T*, T*, std::function<int(T&, T&)>)’
   14 | template <typename T> inline void SortFunc(int ResPlace, int N, T *p, T *buf, std::function<int(T&, T&)> CMP)
      |                                   ^~~~~~~~
sort.cpp:14:35: note:   template argument deduction/substitution failed:
sort.cpp:81:11: note:   mismatched types ‘std::function<int(T&, T&)>’ and ‘int (*)(int&, int&)’
   81 |   SortFunc(0, N, Data, Buf, FuncM);
      |   ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~


Код:
$ g++-10 -v
Using built-in specs.
COLLECT_GCC=g++-10
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 10.2.0-5ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-10-WJNXnb/gcc-10-10.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-10-WJNXnb/gcc-10-10.2.0/debian/tmp-gcn/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (Ubuntu 10.2.0-5ubuntu1~20.04)


на g++-9 - то же самое :(

Скажите, пожалуйста, что я делаю не так?

Спасибо!

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 22:04 
Заслуженный участник
Аватара пользователя


06/10/08
6391
Можно явно указать параметр SortFunc<int>(0, N, Data, Buf, FuncG).
Позже посмотрю подробнее, может быть, что-то можно сделать, чтобы выводился.

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 22:07 


11/08/18
62
Ой, а если явно преобразовывать, то да, все начинает работать:

Используется синтаксис C++
SortFunc(0, N, Data, Buf, (std::function<int(T&,T&)>)FuncM);
 


Спасибо большое!!!

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 22:09 
Заслуженный участник
Аватара пользователя


06/10/08
6391
В принципе можно еще забыть про std::function и сделать
Используется синтаксис C++
template <typename T, typename F> inline void SortFunc(int ResPlace, int N, T *p, T *buf, F CMP)

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение18.01.2021, 22:27 


11/08/18
62
Xaositect в сообщении #1501776 писал(а):
В принципе можно еще забыть про std::function и сделать
Используется синтаксис C++
template <typename T, typename F> inline void SortFunc(int ResPlace, int N, T *p, T *buf, F CMP)

классно, спасибо!!! Это вроде работает и нет нужды в std::function, которую компилер может и не додуматься оптимизировать...

Спасибо большое!!!

 Профиль  
                  
 
 Re: Ламбда при вызове шаблона(C++), почему у меня не получается?
Сообщение23.02.2021, 14:36 
Аватара пользователя


07/02/12
1398
Питер
ilghiz в сообщении #1501778 писал(а):
классно, спасибо!!! Это вроде работает и нет нужды
Вы учтите только, что эта функция будет скопирована TxF раз (для всех комбинаций T и компаратора), разворачивая и сам компаратор, безотносительно - указали вы inline или нет. Что при глубоких вложенностях может быть довольно громоздко.

По существу - т.к. лямбда у вас темплейтная, и <SortFunc> темплейтный, компилятор не знает что делать.
Лечится это явным приведением лямбды к типу функции, должно заработать:
Используется синтаксис C++
int (*Func1)(T&, T&) = [](T& t1, T&t2) -> int { return (t1>t2)?1:0; };
SortFunc(0, N, Data, Buf, Func1);
 
или, соответственно,
Используется синтаксис C++
SortFunc(0, N, Data, Buf, (int (*)(T&, T&)) [](T& t1, T&t2) -> int { return (t1>t2)?1:0; });
 

Но заметьте, что это не будет работать, если лямбда захватывает переменные - т.к. это будет уже не просто функция. В этом случае придется делать немного более сложный промежуточный темплейт или использовать готового монстра std::function

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 10 ] 

Модераторы: Karan, maxal, Toucan, PAV, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group