C++ 中文周刊 第8期

reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态。

每周更新

周刊项目地址 github在线地址知乎专栏

欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue


资讯

编译器信息最新动态推荐关注hellogcc公众号

本周周报github直达

文章

简单概括 负数浮点数转化给无符号整型是ub

double dbl = -123.45; 
int d_cast0 = (unsigned int)dbl; //可能会被优化成0,尤其是arm平台
int d_cast = (unsigned)(int)dbl; 
// d_cast == -123
// works on both. 

参考链接2也解释了,在x86平台的汇编和arm平台汇编不同,gcc、clang、msvc都很统一地为x86-64生成了cvttsd2si,为arm64生成了fcvtzu fcvtzu导致的0

class iapi {
 public:
  virtual ~iapi() = default;
  virtual auto call() const -> int = 0;
};

struct production_api : iapi { auto call() const -> int override { return {}; } };
struct fake_api       : iapi { auto call() const -> int override { return 42; } };

struct app {
  const iapi& api;
};

int main() {
  auto production = boost::di::make_injector(
    boost::di::bind<iapi>.to<production_api>()
  );

  assert(0 == boost::di::create<app>(production).api.call());

  auto testing = boost::di::make_injector(
    std::move(production), // include all production bindings
    boost::di::bind<iapi>.to<fake_api>() [ boost::di::override ]
  );

  assert(42 == boost::di::create<app>(testing).api.call());
}

讲了一个string_view到const char* 的bug

// The Case of string_view and the Magic String 
// -- by Giovanni Dicanio

#include <stdio.h>

#include <iostream>
#include <string>
#include <string_view>

void SomeCApi(const char* name)
{
    printf("Hello, %s!\n", name);
}

void DoSomething(std::string_view name)
{
    SomeCApi(name.data());
}

int main()
{
    std::string msg = "Connie is learning C++";
    auto untilFirstSpace = msg.find(' ');

    std::string_view v{ msg.data(), untilFirstSpace };

    std::cout << "String view: " << v << '\n';

    DoSomething(v);
}

只能说,别这么写,const char*判断结尾和string_view判断结尾并不一致

想让connection只触发一次,触发然后就断开

auto singleShot = [receiver, connection](parameters) {
  QObject::disconnect(connection); // WHOPS, we don't have this yet!
  receiver->slot(parameters);
};
 
connection = connect(sender, &Sender::signal, receiver, std::move(singleShot));

这里的问题在connection在后面才生成,lambda要在前面捕获

改进方案

auto connection = std::make_unique<QMetaObject::Connection>();
auto connectionPtr = connection.get();
 
auto singleShot = [receiver, connection = std::move(connection)](parameters) {
  QObject::disconnect(*connection);
  receiver->slot(parameters);
};
 
*connectionPtr = connect(sender, &Sender::signal, receiver, std::move(singleShot))); 

难受

qt6新方案

connect(sender, &Sender::signal,
       receiver, &Receiver::slot,
       static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));

提供了这个功能

那qt5咋办

这里介绍了他们的工具箱库

KDToolBox::connectSingleShot(sender, &Sender::signal, receiver, &Receiver::slot);
 
sender->causeSignalEmission(); // calls the slot, and breaks the connection
sender->causeSignalEmission(); // does NOT call the slot

第一次causeSignalEmission之后内部自然就disconnection了,也就规避了这个问题,他们的库在这里 https://github.com/KDAB/KDToolBox

直接看代码,继承string,改写char_traits,把traits的方法改写成大小写不敏感就可以了

#pragma once

#include <istream>
#include <ostream>
#include <compare>
#include <string>
#include <locale>
#include <utility>
#include <algorithm>
#include <type_traits>

inline namespace detail
{
	template<typename CharT>
	inline auto char_ieq(CharT c1, CharT c2, const std::locale& loc = std::locale())
	{
		return std::toupper(c1, loc) == std::toupper(c2, loc);
	};

	template<typename CharT>
	inline auto char_ilt(CharT c1, CharT c2, const std::locale& loc = std::locale())
	{
		return std::toupper(c1, loc) < std::toupper(c2, loc);
	};

	template<typename CharT>
	inline auto string_icmp(const CharT* s1, std::size_t n1, const CharT* s2, std::size_t n2, const std::locale& loc = std::locale())
	{
		if(std::lexicographical_compare(s1, s1 + n1, s2, s2 + n2, [&](CharT c1, CharT c2) { return char_ilt(c1, c2, loc); })) return -1;
		if(std::lexicographical_compare(s2, s2 + n2, s1, s1 + n1, [&](CharT c1, CharT c2) { return char_ilt(c1, c2, loc); })) return 1;
		return 0;
	}

	template<typename CharT>
	struct char_itraits : std::char_traits<CharT>
	{
		static auto eq(CharT c1, CharT c2)
		{
			return char_ieq(c1, c2);
		}

		static auto lt(CharT c1, CharT c2)
		{
			return char_ilt(c1, c2);
		}

		static auto compare(const CharT* s1, const CharT* s2, std::size_t n)
		{
			return string_icmp(s1, n, s2, n);
		}
	};
}

template<typename CharT, typename Alloc = std::allocator<CharT>>
class basic_istring : public std::basic_string<CharT, char_itraits<CharT>, Alloc>
{
public:
	using base = std::basic_string<CharT, char_itraits<CharT>, Alloc>;
	using base::base;

	template<typename Traits2, typename Alloc2,
	std::enable_if_t<not std::is_same_v<char_itraits<CharT>, Traits2>, void>* = nullptr>
	basic_istring(const std::basic_string<CharT, Traits2, Alloc2>& str)
	: base(str.data(), str.length()) {}

	operator auto () const
	{
		return std::basic_string<CharT>(this->data(), this->length());
	}

	template<typename Traits2, typename Alloc2>
	std::enable_if_t<not std::is_same_v<char_itraits<CharT>, Traits2>, bool>
	friend operator == (const basic_istring& lhs, std::basic_string<CharT, Traits2, Alloc2>& rhs)
	{
		return string_icmp(lhs.data(), lhs.length(), rhs.data(), rhs.length()) == 0;
	}

	template<typename Traits2, typename Alloc2>
	std::enable_if_t<not std::is_same_v<char_itraits<CharT>, Traits2>, std::strong_ordering>
	friend operator <=> (const basic_istring& lhs, std::basic_string<CharT, Traits2, Alloc2>& rhs)
	{
		return string_icmp(lhs.data(), lhs.length(), rhs.data(), rhs.length()) <=> 0;
	}

	template<typename Traits2, typename Alloc2>
	std::enable_if_t<not std::is_same_v<char_itraits<CharT>, Traits2>, bool>
	friend operator == (std::basic_string<CharT, Traits2, Alloc2>& lhs, const basic_istring& rhs)
	{
		return string_icmp(lhs.data(), lhs.length(), rhs.data(), rhs.length()) == 0;
	}

	template<typename Traits2, typename Alloc2>
	std::enable_if_t<not std::is_same_v<char_itraits<CharT>, Traits2>, std::strong_ordering>
	friend operator <=> (std::basic_string<CharT, Traits2, Alloc2>& lhs, const basic_istring& rhs)
	{
		return string_icmp(lhs.data(), lhs.length(), rhs.data(), rhs.length()) <=> 0;
	}
};

using istring = basic_istring<char>;
using iwstring = basic_istring<wchar_t>;

inline auto& operator >> (std::istream& is, istring& istr)
{
	std::string temp;
	is >> temp;
	istr = std::move(temp);
	return is;
}

inline auto& operator >> (std::wistream& wis, iwstring& iwstr)
{
	std::wstring temp;
	wis >> temp;
	iwstr = std::move(temp);
	return wis;
}

inline auto& operator << (std::ostream& os, const istring& istr)
{
	os << istr.c_str();
	return os;
}

inline auto& operator << (std::wostream& wos, const iwstring& iwstr)
{
	wos << iwstr.c_str();
	return wos;
}

inline auto operator ""_is(const char* istr, std::size_t len)
{
	return istring(istr, len);
}

inline auto operator ""_iws(const wchar_t* iwstr, std::size_t len)
{
	return iwstring(iwstr, len);
}

结论,除非spinlock有范围重叠 overlap(互相引用) 否则不会发生死锁

视频

就是检查是否以xx开头以xx结尾,string小工具

项目


本文永久链接

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账