HLFX.Ru Forum
Показать все 35 сообщений этой темы на одной странице

HLFX.Ru Forum (https://hlfx.ru/forum/index.php)
- Технические вопросы (https://hlfx.ru/forum/forumdisplay.php?forumid=20)
-- с++: опять запутался в трёх соснах. (https://hlfx.ru/forum/showthread.php?threadid=4795)


Отправлено thambs 30-06-2016 в 12:29:

с++: опять запутался в трёх соснах.

Понадобился мне тут класс для квадратных матриц, но не могу понять что за ошибка лезет:

C++ Source Code:
1
#define self (*this)
2
template <typename T>
3
class CMatrix{
4
  T *data = NULL;
5
public:
6
  size_t size;
7
public:
8
  CMatrix(size_t n): size(n){
9
    data = new T [size*size];
10
  }
11
  CMatrix(const CMatrix& other){
12
    size = other.size;
13
    data = new T [size*size];
14
    for(size_t x=0; x<size; x++){
15
      for(size_t y=0; y<size; y++){
16
        //вот так работает
17
        data[size*x+y] = other.data[size*x+y];
18
        //а вот так хрен вам!
19
        self(x,y) = other(x,y);
20
        // получаем error: passing ‘const CMatrix<float>’ as ‘this’ argument of ‘T& CMatrix<T>::operator()(const size_t&, const size_t&) [with T = float; size_t = long unsigned int]’ discards qualifiers [-fpermissive]
21
      }
22
    }
23
  }
24
  ~CMatrix(){
25
    delete [] data;
26
  }
27
  T &operator()(const size_t& x, const size_t& y){
28
    return data[size*x+y];
29
  }
30
}

Как это по человечески сделать?

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено FreeSlave 30-06-2016 в 12:42:

thambs, ты пытаешься вызвать неконстантную функцию на константном объекте (other).

Нужно продублировать оператор скобок с квалификатором const:

code:
T operator()(const size_t& x, const size_t& y) const { return data[size*x+y]; }


Отправлено Дядя Миша 30-06-2016 в 19:06:

Цитата:
thambs писал:
#define self (*this)

улыбнуло

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено pRoxxx 01-07-2016 в 14:34:

А чем тебе работающий вариант не подходит? Или у тебя задача сделать код максимально не читаемым?


Отправлено thambs 20-07-2016 в 18:05:

А подскажите про Variadic functions -- я уже себе весь мозг сломал. Везде эта зараза требует что бы был указан хотя бы один аргумент. Мне нужно, что бы можно было единообразно вызвать функцию от любого (и нулевого) числа однотипных аргументов, а их колчиество задавалось, например, в шаблоне. Как тогда обойтись без va_start?

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено XaeroX 20-07-2016 в 18:37:

Цитата:
thambs писал:
Везде эта зараза требует что бы был указан хотя бы один аргумент.

Нет, это не так. Вернее, это так только для С. В С++ ты можешь спокойно скомпилить вот такое:
C++ Source Code:
int foo(...) { return 42; }

Цитата:
thambs писал:
Как тогда обойтись без va_start?

Необходимость сочетать va_start и шаблоны - признак плохого стиля кодирования. Используй std::initializer_list или variadic templates.
Если всё же есть желание натягивать сову на глобус - могу предложить получать доступ к аргументам напрямую из стека, используя ассемблерные вставки.
__asm в шаблонах гарантированно снесёт мозг любому код-ревьюверу. )

__________________

xaerox on Vivino


Отправлено thambs 20-07-2016 в 19:01:

>std::initializer_list или variadic templates
нашёл вот такой http://nerdparadise.com/forum/openmic/5712/ вариант, но как-то через рекурсивный шаблон уродливо. Получается, придётся на каждую функцию завершающий дублёр писать... Это уже haskell какой-то получается.
>ассемблерные вставки
это плохо, хотелось бы чего ни будь в стиле:

C++ Source Code:
f(int xs...){
  for(n=0;n<n_dim;n++) x=xs[n];
}

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено XaeroX 20-07-2016 в 22:03:

Цитата:
thambs писал:
это плохо, хотелось бы чего ни будь в стиле

Не факт, что все аргументы будут одного типа. Более того, не факт, что все они одного размера.
Но в принципе std::initializer_list как раз и делает то, что тебе нужно.

__________________

xaerox on Vivino


Отправлено Дядя Миша 21-07-2016 в 16:39:

Цитата:
XaeroX писал:
Вернее, это так только для С. В С++ ты можешь спокойно скомпилить вот такое:

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

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено thambs 21-07-2016 в 16:47:

>имя уже необязательно
А доступ к ним как получать?
>std::initializer_list
Вызов будет f({arg1, arg2, ...}), эти скобки убрать что бы выглядело как обычная функция.

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено Дядя Миша 21-07-2016 в 17:25:

Цитата:
thambs писал:
А доступ к ним как получать?

ну, через ассемблер к примеру по смещению. Или как-нибудь получить указатель на функцию внутри самой себя и посчитать смещение до первого аргумента (+4 байта). Но я не уверен что компилятор такое прожует, да и ни к чему это.

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено ComradeAndrew 21-07-2016 в 18:07:

thambs
А такой вариант устраивает?

C++ Source Code:
1
template<typename... Ts> void func(Ts... args){
2
  const int size = sizeof...(args) + 2;
3
  int res[size] = {1,args...,2};
4
  // since initializer lists guarantee sequencing, this can be used to
5
// call a function on each element of a pack, in order:
6
  int dummy[sizeof...(Ts)] = { (std::cout << args, 0)... };
7
}

source
Если в функцию не подается аргументов, то можно использовать либо константную проверку (правда она вроде только в C++17)
Ну или можно использовать std::vector
C++ Source Code:
std::vector<int> v{ args... };

Ну смысл ты понял.


Отправлено thambs 21-07-2016 в 21:04:

ComradeAndrew
Вот это то что надо, только я не могу понять как оно работает:

C++ Source Code:
const int n_args = sizeof...(args);
int dummy[n_args] = { args... }; //вот тут оно разворачивается вообще без проверки типов, или там есть неявное приведение?
в чём разница между
C++ Source Code:
sizeof...(args)
и
C++ Source Code:
sizeof...(Ts)
?

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено ComradeAndrew 22-07-2016 в 06:51:

thambs
Никакой разницы. И то и то компилируется вот в это

code:
const int size = sizeof...(args); mov dword ptr [size],2 const int sizeTs = sizeof...(Ts); mov dword ptr [sizeTs],2

С двумя аргументами соответственно.

Для вызовов с различными параметрами генерится соответствующая функция.

Добавлено 22-07-2016 в 09:51:

Цитата:
ComradeAndrew писал:
int dummy[n_args] = { args... }; //вот тут оно разворачивается вообще без проверки типов, или там есть неявное приведение?

Разворачивание происходит на этапе компиляции. Это будет обычная декларативная инициализация(или как это называется).


Отправлено thambs 22-07-2016 в 16:17:

ComradeAndrew
По смыслу получается, что функция принимает аргументы по значению (т.е. копирует их), а потом ещё раз копирует внутрь массива int dummy[]? Можно ли добиться поведения аналогичного передаче по ссылке?
И ещё вопрос -- а можно сделать количество однотипных аргументов параметром шаблона?

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено ComradeAndrew 23-07-2016 в 05:41:

thambs

Цитата:
thambs писал:
Можно ли добиться поведения аналогичного передаче по ссылке?

Ну передавай указатели. Потому что
no arrays of references

Цитата:
а можно сделать количество однотипных аргументов параметром шаблона?

Не понял что ты хочешь сделать.


Отправлено Дядя Миша 23-07-2016 в 13:42:

Цитата:
ComradeAndrew писал:
Потому что
no arrays of references

К слову сказать подобные ограничения свидетельствуют о непродуманности архитектуры языка в целом. Да и не только языка, а вооббще любого продукта. Интуитивно понятное обучение строится на аналогиях и человек привыкший делать массивы из указателей естественно будет пытаться провернуть подобное и со ссылками. А потом конечно выходят книжки "как делать нельзя". Вообще большинство книжек по крестам учит именно тому чего делать нельзя.

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено FiEctro 23-07-2016 в 14:39:

Дядя Миша
ИМХО как делать нельзя должен сообщать компилятор, а не книжки

__________________
У котёнка мокрый нос и гладенькая шерсть, у него забавный хвост и быстрых лапок шесть. Две задних, две средних и две передних лапы, такая многоножка получилася у папы.
Он ученый — папа мой — зверушек изучает, гуляет по помойкам, ловит крыс и чаек. Две крысы белокрылые и чайки две унылые покрытые пупырчатою кожей лягушат без пёрышек тоскуют и ускакать спешат.
А ещё есть муравей большой размером с гуся он пугает всех зверей, и я его боюся, когда он ковыляет на лапках на своих.
И в двери ударяет, и начинает стих: Я — муравей, воды налей! Не меньше ведра, напиться мне пора!


Отправлено Дядя Миша 23-07-2016 в 14:53:

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

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено XaeroX 23-07-2016 в 15:57:

FiEctro
Компилятор и сообщает, но все почему-то потом к нам на форум идут, с уточняющими вопросами.

__________________

xaerox on Vivino


Отправлено Дядя Миша 23-07-2016 в 17:27:

Цитата:
XaeroX писал:
но все почему-то потом к нам на форум идут, с уточняющими вопросами.

а наша задача - отредиректить их на три весёлых буквы, на CSM тоесть.

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено XaeroX 23-07-2016 в 18:13:

Цитата:
Дядя Миша писал:
отредиректить их на три весёлых буквы, на CSM тоесть.

Как говорил Охлобыстин в известном сериале - на ЭКГ!

__________________

xaerox on Vivino


Отправлено thambs 24-07-2016 в 14:50:

>no arrays of references
Это понятно. Я другое имел ввиду. Сейчас у меня функция выглядит так:

C++ Source Code:
1
template<typename...Is>
2
inline T& operator () (Is...args){
3
  const int n_args = sizeof...(args);
4
  int xs[n_args] = {((int)args)...};
5
  int i = 0; for(int n=0; n<n_args; n++) i += xs[n] * helper[n];
6
  return data[i];
7
}

т.е. сначала аргументы копируются в args, потом из args повторно копируются в xs. Если я правильно понимаю как работает компилятор, то при передаче параметра по ссылке ничего никуда не копируется, а при обращении к соответствующему аргументу просто подставляется его адрес. Соответственно, хотелось бы, что бы шаблон разворачивался во что ни будь типа:
C++ Source Code:
T& operator () (int& arg1, int& arg2, int& arg3, int& arg4)

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

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено ComradeAndrew 24-07-2016 в 20:00:

thambs
Так ты хочешь изменять аргументы, беря их по ссылке, или ты так пытаешься "оптимизировать" код?
Если второе, то забудь. Ассемблерный код почти не отличается, особенно когда ты потом кладешь все аргументы в массив под который выделяется память в любом случае. Да и не думай, что ты умнее компилятора и процессора в 2016 году, когда пишешь на плюсах.

Ну если сильно хочется, то можешь сделать так:

C++ Source Code:
template<typename...Ts>
void func (Ts&...args)


Отправлено Дядя Миша 24-07-2016 в 20:08:

Цитата:
ComradeAndrew писал:
Да и не думай, что ты умнее компилятора и процессора в 2016 году

а компилятор што, не люди писали?

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено XaeroX 24-07-2016 в 20:15:

Цитата:
ComradeAndrew писал:
Да и не думай, что ты умнее компилятора и процессора в 2016 году, когда пишешь на плюсах.

Забавно, но я слышу эту фразу вот уже 16 лет, в ней меняется только год.
А потом выясняется, что компилятор какой-нибудь 2010-й студии не умеет нормально max скомпилировать, и далее в этом же духе.
Компилятор - он не умный, он педантичный. В том смысле, что не может сделать ошибку по невнимательности, что характерно для человека. В остальном же - дуб дубом.

__________________

xaerox on Vivino


Отправлено ComradeAndrew 24-07-2016 в 20:45:

Цитата:
Дядя Миша писал:
а компилятор што, не люди писали?

Где я такое сказал?

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

thambs
Кстати, раз уж пишешь на плюсах, то можешь использовать такую распаковку, когда надо для каждого аргумента одно и тоже сделать:
C++ Source Code:
1
#include <initializer_list>
2
 
3
template<typename...Is>
4
int sum (Is&...args) {
5
  int s = 0;
6
  auto add = [&s](int arg) { s+=arg; }; // Лямба-функция
7
  if (sizeof...(args))
8
    std::initializer_list<int>({ (add(args), 0)... });
9
  return s;
10
}


Отправлено XaeroX 24-07-2016 в 20:55:

ComradeAndrew
Я не говорю - всё бросить и оптимизировать. Я предлагаю избегать пессимизации, понадеявшись на мудрость компилятора. Некоторые этим грешат, увы.

__________________

xaerox on Vivino


Отправлено Дядя Миша 24-07-2016 в 21:18:

Цитата:
ComradeAndrew писал:
Где я такое сказал?

Ты - нигде. Поэтому я тебя и спросил.

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'


Отправлено thambs 24-07-2016 в 21:27:

А можешь пояснить (или лучше кинуть статьёй) как вот эта распаковка работает?

C++ Source Code:
std::initializer_list<int>({ (add(args), 0)... });
//Конкретно, не понятно, для чего 0 в (add(args), 0) и как вообще подскобочное выражение работает.

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

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено ComradeAndrew 25-07-2016 в 06:14:

Цитата:
thambs писал:
А можешь пояснить (или лучше кинуть статьёй) как вот эта распаковка работает?

Ну я как правило все ответы нахожу на stackoverflow.com и en.cppreference.com.
В данном случае это все написано тут и тут.

Если коротко, то распаковка варьируемых аргументов может происходить только в конструкции list-initializer. В моем примере я использую лямда функцию в которую распаковываются аргументы и она ничего не возвращает, поэтому и дописываю 0 в список инициализации, через запятую. И получаю такую конструкцию:
C++ Source Code:
{ (add(args), 0)... } // ... - для распаковки

Соответственно я эту конструкцию должен использовать только там, где применяется list-initializer. Например как аргумент для std::initializer_list.
Это может быть и объявление массива, вроде int a[] = { args... };
Ну я думаю суть ты понял.


Отправлено thambs 25-07-2016 в 08:37:

ComradeAndrew
Спасибо, вот что, собственно, я искал:

C++ Source Code:
for (const auto& arg : {Args...})

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

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено thambs 16-08-2016 в 03:08:

Вопрос про шаблоны. Пусть есть шаблон функции параметризуемый параметром:

C++ Source Code:
enum ptype {TYPE1, TYPE2, TYPE3};
template<ptype T> void foo(void);

Очень хочется сделать конструкцию в стиле
C++ Source Code:
for(const auto T: {TYPE1, TYPE2, TYPE3})
  foo<T>();

что бы оно при компиляции развернулось в
C++ Source Code:
foo<TYPE1>();
foo<TYPE2>();
foo<TYPE3>();

Как такое можно организовать?

__________________
http://www.moddb.com/mods/monorail-quest


Отправлено XaeroX 16-08-2016 в 08:02:

thambs
Например, вот так:

C++ Source Code:
1
enum ptype { TYPE1, TYPE2, TYPE3, TYPE_END };
2
template<ptype T> void foo(void);
3
 
4
template<ptype T> void until_ptype_end()
5
{
6
  foo<T>();
7
  until_ptype_end<static_cast<ptype>(T+1)>();
8
}
9
template<> void until_ptype_end<TYPE_END>() {}

И вызываем вот так:
C++ Source Code:
until_ptype_end<TYPE1>();

Этот код корректно работает и со специализациями foo. Но есть ограничение: элементы енума должны быть последовательными (т.к. доступ к следующему вычисляется как предыдущий + 1).

__________________

xaerox on Vivino


Отправлено thambs 17-08-2016 в 21:20:

Блин, или я идиот, или одно из двух... Сделал две реализации -- одну на шаблонах, а другую на статичных массивах с указателями на функции. Казалось бы, что шаблоны развернутся прямо в нужные функции, и это будет быстрее чем обращаться через обёртку -- но нет, через обёртку процентов на 10% быстрее. wat?

__________________
http://www.moddb.com/mods/monorail-quest


Временная зона GMT. Текущее время 16:44.
Показать все 35 сообщений этой темы на одной странице

На основе vBulletin версии 2.3.0
Авторское право © Jelsoft Enterprises Limited 2000 - 2002.
Дизайн и программирование: Crystice Softworks © 2005 - 2024