LINUX.ORG.RU

Сообщения kvpfs

 

Передать в parameter pack индексы

Товарищи, хочется так:

#include <array>
#include <tuple>
using namespace std;

struct Q {
    void set(int i) {}
};

template <int I>
struct S {
    Q mq[I];
    template <size_t ...num>
    void f(array<int, I> &a,
            index_sequence<num...> n=make_index_sequence<I>{}) {
        ((mq[num].set(a[num])), ...);
    }
};

int main() {
    S<3> s;
    array a{2, 5, 7};
    s.f(a);
}

Но почему-то не выходит передать make_index_sequence{} в качестве дефолтного аргумента. Работает, если над f вызовом накостылить обёртку:

	template <size_t ...num>
	void f_ok(array<int, I> &a) {
		f(a, make_index_sequence<I>{});
	}

и дёргать её, но наличие доп сущности восторг не вызывает. Может есть ещё какой вариант передать в parameter pack индексы без подобного (f_ok()) костыля?

 

kvpfs
()

Удалить из строки ударение и подобное

Всем здрасьте.
Взял я boost::locale для операций с Юникодом, и пока не понял - а как удалить из строки знаки ударения (хотя там может быть и другой мусор однозначно). С наскоку сделал декомпозицию с case folding’ом - не помогает:

#include <boost/locale.hpp>
#include <iostream>
#include <string>
#include <locale>
using namespace boost::locale;
using namespace std;
 
int main() {
	wstring str = L"фыва\u00b4"; // "фыва" с ударением на 'а'
	generator gen;
	locale::global(gen(""));
	wstring res = normalize(str, boost::locale::norm_nfd);
	fold_case(res);
	cout << str.size() << "  " << res.size() << endl;
}

// cout: 5 5

На стековерфлоу есть подобный вопрос, там советовали вручную парсить строку для поиска ударений, это явно странно. Как правильно?

 , , , ,

kvpfs
()

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

Приветствую.
Гипотеза - на каждой нормальной клавиатуре, ориентированной на представителя любой культуры говорящего на любом языке на клавишах вторым рядом выбита латиница.

Как без заморочек о типах раскладок (всякие QWERTY и AZERTY) получить латинскую букву передав на вход что-то из нелатинской раскладки? Например:

char translate(wchar_t sym);
cout << translate(L'й')
     << translate(L'ц')
     << translate(L'у')
     << translate(L'к')
     << translate(L'е')
     << translate(L'н');
// cout: qwerty

Т.е. какая-то либа, которая спросит у системы тип клавиатуры, может раскладки, и даст ответ, на регистр можно забить и всегда выдавать в нижнем или верхнем.

 

kvpfs
()

Заменить SFINAE или концепты на if constexpr, почему нет?

Привет. Не могу понять, почему не получается заменить это:

#include <tuple>
#include <type_traits>
using namespace std;

template <typename Tuple, size_t i=0>
requires (i >= tuple_size_v<Tuple>)
consteval bool check_visitor() {
	return true;
}

template < typename Tuple, size_t i=0>
requires (i < tuple_size_v<Tuple>)
consteval bool check_visitor() {
	static_assert(! is_same_v<tuple_element_t<i, Tuple>, bool>);
	return check_visitor<Tuple, i+1>();
}

int main() {
	using T = tuple<int, double, char>;
	check_visitor<T>();
}

на это:

#include <tuple>
#include <type_traits>
using namespace std;

template < typename Tuple, size_t i=0>
consteval bool check_visitor() {
	static_assert(! is_same_v<tuple_element_t<i, Tuple>, bool>);
	if constexpr (i < tuple_size_v<Tuple>)
		return check_visitor<Tuple, i+1>();
	else
		return true;
}

int main() {
	using T = tuple<int, double, char>;
	check_visitor<T>();
}

Выражение в if constexpr зависит от параметров шаблона, как говорит справочник - в таком случае неактивная ветка должна полностью исчезнуть при инстанцировании, хоть ODR используй там необъявленное.

 

kvpfs
()

Повесть несколько команд на сочетание клавиш

Привет.
Есть в виме terminal mode, мне вполне нравится, но есть одно но - отсутствует возможность отчистить терминальный буфер. В целом это не проблема - сделал так:

function Clear_terminal()
	if winnr('$') == 1
		let l:only_window = 1
	else
		let l:only_window = 0
	endif
	bd!
	terminal
	if only_window
		only
	endif
endfunction

function Terminal_started()
	setlocal nonumber
	nmap <buffer> <C-w>l :call Clear_terminal()<CR>
endfunction

augroup Mode_hooks_group
	autocmd!
	...
	autocmd TerminalOpen * call Terminal_started() 
augroup End

Но есть одна проблема - вызвать Clear_terminal() я могу лишь в нормальном режиме (внутри Terminal mode), в режиме ввода команд сделать этого никак не получается. Всякие наивные попытки вроде

tmap <C-w>l <C-w>N<C-w>l "выход в нормальный режим, а следом ввод <C-w>l для вызова функции

проваливаются, происходит выход в норм режим, а вторая часть этой комплексной команды игнорится. Как из режима вставки дёрнуть Clear_terminal()? Т.е одним нажатием <C-w>l без ручного выхода в норм режим.

 ,

kvpfs
()

Сходить на сайт по ip

Для примера возьмём адрес «https://www.wikipedia.org», который норм открывается в обозревателе, задача - сходить на него имея на руках его ip адрес (т.е. без обращения к dns).

$ dog www.wikipedia.org
CNAME www.wikipedia.org.  23h59m10s   "dyna.wikimedia.org."
    A dyna.wikimedia.org.     9m10s   91.198.174.192
$ ping 91.198.174.192
PING 91.198.174.192 (91.198.174.192) 56(84) bytes of data.
64 bytes from 91.198.174.192: icmp_seq=1 ttl=58 time=144 ms

Далее в адресной сроке обозревателя ввожу «https://91.198.174.192», получаю жалобу на невалидный сертифика (что ок и вопросов не вызвает), соглашаюсь с рисками и в итоге не получаю ожидаемую страницу. Не заканчиваются успехом и попытке вроде «91.198.174.192:443».

Что я не так делаю и как правильно?

 ,

kvpfs
()

Видите ли вы в коде какие-нибудь проблемы?

Всем привет. Локализовал код, на который жалуется санитайзер. Не вижу здесь своей ошибки, а вы?

#include <thread>
#include <atomic>
#include <mutex>
#include <vector>
#include <chrono>
using namespace std;

class Test {
	mutex m_mtx;
	atomic_flag m_spin_lock;
	vector<int> m_data;
public:
	void add() {
		while (m_spin_lock.test_and_set(memory_order_relaxed))
			this_thread::yield();
		atomic_thread_fence(memory_order_acquire);
		while (true) {
			this_thread::sleep_for(300ms);
			std::scoped_lock lck{m_mtx};
			m_data.push_back(4);
		}
		m_spin_lock.clear(memory_order_release);
	}
	void read() {
		size_t sz;
		while (true) {
			if (! m_spin_lock.test_and_set(std::memory_order_acquire)) {
				sz = m_data.size();
				m_spin_lock.clear(std::memory_order_release);
			}
			else {
				std::scoped_lock lck{m_mtx};
				sz = m_data.size();
			}
			this_thread::sleep_for(1s);
		}
	}
}test;

int main() {
	jthread rt(&Test::read, &test);
	this_thread::sleep_for(10ms);
	test.add();
}
$ g++ 1.cc -std=c++20 -fsanitize=thread
$ ./a.out
WARNING: ThreadSanitizer: data race (pid=63269)
  Write of size 8 at 0x56247be53a80 by main thread (mutexes: write M11):
    #0 void std::vector<int, std::allocator<int> >::_M_realloc_insert<int>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int&&) <null> (a.out+0xd9a47)
    #1 int& std::vector<int, std::allocator<int> >::emplace_back<int>(int&&) <null> (a.out+0xd970c)
    #2 std::vector<int, std::allocator<int> >::push_back(int&&) <null> (a.out+0xd9595)
    #3 Test::add() <null> (a.out+0xd819b)
    ...

  Previous read of size 8 at 0x56247be53a80 by thread T1:
    #0 std::vector<int, std::allocator<int> >::size() const <null> (a.out+0xd899d)
    #1 Test::read() <null> (a.out+0xd7bc2)
    ...

Со шлангом аналогично.

 ,

kvpfs
()

Data race

Санитайзер говорит о рейсах здесь, объясните мне пожалуйста - что здесь не так? Всё под мьютексом.

#include <mutex>
#include <thread>
#include <chrono>
#include <condition_variable>
#include <queue>
#include <memory>
using namespace std;

struct Mes {
	int data = 0;
	bool processed = false;
};

struct Test {
	mutex mtx;
	condition_variable cv;
	queue<weak_ptr<Mes>> mes_queue;
	int read();
	bool check();
} t;

int Test::read()
{
	auto sh_ptr = make_shared<Mes>();
	unique_lock lck{mtx};
	mes_queue.push(sh_ptr);
	while (! cv.wait_for(lck, 1s, [&sh_ptr](){
				return sh_ptr->processed == true;})  &&  true);
	return sh_ptr->data;
}

bool Test::check()
{
	scoped_lock lck{mtx};

	bool ret = mes_queue.size();
	while (mes_queue.size()) {
		if (shared_ptr<Mes> mes = mes_queue.front().lock()) {
			mes->data = 5;
			mes->processed = true;
		}
		mes_queue.pop();
	}
	cv.notify_all();
	return ret;
}

void read_th() {
	while (true) {
		t.read();
		this_thread::sleep_for(200ms);
	}
}

void check_th() {
	while (true) {
		t.check();
		this_thread::sleep_for(200ms);
	}
}

int main() {
	jthread tr{read_th};
	jthread tc{check_th};
}

$ g++ -pthread -std=c++20 -fsanitize=thread test.cc

Выхлоп санитайзера весьма обилен, вставил сюда, но главное то, что жалобы на рейсы в полностью валидном коде (на мой взгляд).

 ,

kvpfs
()

Локализовать гнилую оптимизацию

Привет, проблема в следующем - имеется проект, без оптимизаций всё нормально работает, с оптимизациями ГЦЦ выдаёт криво работающую поделку, шланг нормальную. Включил все возможные воринги - ничего серьёзного. Адресный санитайзер проблем не находит. -fsanitize=undefined - аналогично, но с ним ошибка пропадает и софтина работает годно.

Чувствую, что проблема в ГЦЦ, но как подступиться и состряпать баг репорт - не могу сообразить. Ну не слать же портянку в несколько К строк, кто там разбираться с ней будет. Можно ли ткнуть в какую-то сущность в коде и отседить производимые оптимизации над ней?

 ,

kvpfs
()

Нескучные обои

 ,

kvpfs
()

Вы тут сидите и ничего не знаете!

Совершенно случайно наткнулся, в стд появилась мега фича ssize()! После долгий метаний относительно signed/unsigned геморроя, сегодня решил - ну буду к каждому проекту присобачивать костылики - sigsize() и idx(), оказалось, что один костыль не нужен. Ещё бы такую перегрузку для контейнеров воткнуть:

operator[]( ptrdiff_t pos );

Жаль проблемы с неоднозначностью будут. Ладно, может чего придумают на этот счёт, ну а пока такое:

template <typename T>
auto &idx(T &container, std::ptrdiff_t i) {
    return container[static_cast<std::size_t>(i)];
}

Короче - наверняка есть много людей с тонной static_cast’ов в коде - берите ssize() на вооружение.

PS: да, конечно же знаю про *(ctr.begin() + i).

 

kvpfs
()

Автовывод параметров шаблона

Превит.

Имеется конкретная задача (хотелка) - передавать в конструктор brace list, автоматически выводитьс size_t параметра шаблона равный количеству членов листа, обойтись без макросов (с макросами знаю как). Т.е:

template <size_t Sz>
struct S {
   S(...);
};

int main() {
   array<int, 5> a;
   S s{ {1,2,3} };
   S s2(a);
}

Свои соображения:
Видимо задача должна сводится к написанию deduction гида, из brace list’a может быть выведен initializer_list (но не std::array, например). Метод initializer_list::size() - constexpr, по идее можно использовать для передачи аргументом в шаблонный парметр, но не выходит

#include <array>
#include <initializer_list>
using namespace std;

template <size_t U>
struct S {
   S(array<int, U>) {}
};
S(initializer_list<int> l) -> S<l.size()>; // error, можно просто 3, тогда ок, в данном случае

int main() {
   S s2{ {3,4,5} };
}

Есть такой вариант

template <size_t U>
struct S {
    S(const int(&ar)[U]) {}
};

int main() {
   array<int, 5> a;
   S s2{ {3,4,5} }; #1
   S s2(a);         #2 error
}

Но не годится, т.к. #2 не работает. Как бы написать такой хитрый гид? Не вижу причин, которые бы делали невозможным использование компайл тайм инфы о размере std::initializer_list.

 

kvpfs
()

Получить тип возвращаемого значения из лямбды

Нюанс в том, что незивестен точный тип лямбды, они приходят из пользовательского кода, следовательно мне неизвестны типы и количество аргументов, которые функтор ожидает, т.е. я не могу использовать invoke_result<>. Нужно заглянуть в класс, схватить любой оператор() и вернуть тип возврата. Получилось такое:


template <typename T>
struct Return_type;
template <typename R, typename... Args>
struct Return_type<R(Args...)> {using type = R;};
template <typename R, typename Q, typename... Args>
struct Return_type<R (Q::*)(Args...)const> {using type = R;};
template <typename R, typename Q, typename... Args>
struct Return_type<R (Q::*)(Args...)> {using type = R;};

struct A{
	struct V {
		double operator()(int t)const {return 5;}
	};
};

int main() {
	auto l = [](double a, int e)mutable{return 2;};
	auto l2 = [](int a){;return 2;};
	Return_type<decltype(&decltype(l)::operator())>::type a;
	Return_type<decltype(&decltype(l2)::operator())>::type a2;
	Return_type<decltype(&A::V::operator())>::type a3;


	auto l3 = [](auto b){;return 2;};
	Return_type<decltype(&decltype(l3)::operator())>::type a4;

	return 0;
}

И в принципе свою задачу я решил, мне этого хватит, но не знаю как (и возможно ли вообще) получить тип от лямбды, внутри которой шаблонный оператор() (тот, что auto l3). Решаема ли задача в случае с l3?

 

kvpfs
()

Одна code point (или последовательность) == одна графема

Здрасьте. Чтобы не было путаницы в терминологии - под графемой понимаю что-то рисуемое на экране, занимаемое ровно одно знакоместо. Нужен алгоритм, который принимает на вход utf-8 строку и выдаёт на выходе число, которое равно количеству знакомест, которые занимает данная строка будучи отрисованной в терминале.

Но тут подстава со всякими управляющими символами, например Tab, котороый займет некоторое число знакомест, лазить в кишках terminfo для определения этого числа я точно не хочу. Решил поступить проще - итерироваться по символам и проверять является ли символ управляющим и если да, то менять его на пробел. И вот здесь встает вопрос - есть ли управляющие символы выше ASCII диапазона, которые могуть выдать что-то в терминал занимающее более одного знакоместа? Т.е. речь идёт о том, что делать ли std::iscntrl(char_sym, get_locale()) напрямую или конвертить предварительно всю последовательность в wchar_t и уже потом тестить. Естественно, что первое проще, а может второе и вовсе смысла не имеет. Управляющие символы там точно есть (U+2028, например), но рисуется в терминале одним знакоместом.

Я уже почти созрел до того, чтобы закрыть для себя вопрос юникода навсегда и остановиться лишь на в ASCII в софте, по крайней мере до момента, пока не появится адекватная либа, а не ICU. Была зыбкая надежда на boost.locale, но оказалось, что тот же U+2028 она не считет управляющим (тогда как локаль созданная дефолтными с++ средствами считает)

    wchar_t w = L'\u2028';
    cout << std::boolalpha 
        << std::iscntrl(w, boost::locale::generator()("en_US.UTF-8")) << endl
        << std::iscntrl(w, std::locale("en_US.UTF-8")) << endl;

$ ./a.out
false
true

В общем вопросы к ней появились.

 , ,

kvpfs
()

RSS подписка на новые темы