简单地说,以下断言是否会引发火灾?
template<typename T>
auto destructor()
{
return +[](void* p){
((T*)p)->~T();
};
}
assert(destructor<int>() != destructor<char>());
Run Code Online (Sandbox Code Playgroud)
标准似乎只是说lambda转换函数指针与lambda本身做同样的事情,然后你意识到简单的破坏类型都有无操作析构函数,因此是相同的.
假设我们有一个可以将东西写入输出的类
class Writer
{
public:
int write(const std::string& str);
int write(const char* str, int len);
//...
};
Run Code Online (Sandbox Code Playgroud)
我很好,这很灵活,所有这一切,直到我意识到
char* buf = new char[n]; //not terminated with '\0'
//load up buf
Writer w;
w.write(buf); //compiles!
Run Code Online (Sandbox Code Playgroud)
那是一个非常讨厌的错误.
我们可以用一些模板来修改
class WriterV2
{
public:
int write(const std::string& str);
int write(const char* str, int len);
template<typename... Args>
int write(const char*, Args...)
{ static_assert(sizeof...(Args) < 0, "Incorrect arguments"); }
//...
};
Run Code Online (Sandbox Code Playgroud)
但这种方法存在问题
WriterV2 w;
w.write("The templating genius!"); //compile error
Run Code Online (Sandbox Code Playgroud)
我该怎么办?什么是更好的设计?
在任何人问之前,重载const char (&)[N] …
这个问题的灵感来自标准中的一个注释[class.mem]
非静态成员函数的类型是普通函数类型,非静态数据成员的类型是普通对象类型.没有特殊的成员函数类型或数据成员类型.
所以,我决定测试一下
struct S
{
using Fn = void();
Fn foo;
static_assert(std::is_same_v<decltype(foo), Fn>);
};
Run Code Online (Sandbox Code Playgroud)
但它的错误在于decltype(foo):无效使用非静态成员fucntion.
你如何获得成员函数的类型?或者笔记是假的?
注意:对数据成员执行此操作是有效的
struct U
{
int i;
static_assert(std::is_same_v<decltype(i), int>);
};
Run Code Online (Sandbox Code Playgroud)
注2:我不是在寻找如何通过指向成员的指针来获取类型
template<typename>
struct NotLikeThis;
template<typename C, typename R, typename... Args>
struct NotLikeThis<R (C::*)(Args...)>
{
using type = R(Args...);
};
Run Code Online (Sandbox Code Playgroud)
标准中的注释与此无关.
这是读取普通可复制对象的字节的常用方法
Object obj;
auto p = reinterpret_cast<char*>(&obj);
for(size_t i = 0; i < sizeof(obj); i++)
consume(p[i]);
Run Code Online (Sandbox Code Playgroud)
问题不在于严格别名,char*而是允许别名.问题出在[expr.add]的这段话
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果表达式
P指向具有元素x[i]的数组对象x的n元素,则表达式P + J和J + P(其中J具有值j)指向(可能是假设的)元素x[i + j]if0 ? i + j ? n; 否则,行为未定义.同样,表达式P - J指向(可能是假设的)元素x[i ? j]if0 ? i ? j ? n; 否则,行为未定义.
假设元素所指的地方
过去的阵列的最后一个元素的指针
x的n元素被认为是等效的指针的假想元件x[n]用于此目的的 …
在潜入动态记忆的过程中,我发现看起来矛盾的是琐碎的类型如何开始它们的生命.考虑一下片段
void* p = ::operator new(sizeof(int)); // 1
// 2
new (p) int; // 3
Run Code Online (Sandbox Code Playgroud)
什么时候int开始它的生命?
仅获取存储,::operator new指定具有效果(来自[new.delete.single])
new-expression调用的分配函数用于分配大小的存储字节.[...]分配适当对齐的存储空间以表示该大小的任何对象,前提是对象的类型没有新扩展的对齐方式.
鉴于获取存储不足以创建对象,int因此无法在此处开始其生命周期.
此时,int已经获得了适合的存储空间.
这int是由新位置创建的.但不知何故,它的生命没有从这里开始,因为来自[basic.life]
[...]如果一个对象属于类或聚合类型,并且它或其子对象之一由除了普通默认构造函数之外的构造函数初始化,则称该对象具有非空的初始化.类型对象的生命周期从以下时间
T开始:
获得具有适当对齐和类型大小的存储
T,并且如果对象具有非空的初始化,则其初始化完成[...]
int既不是类也不是聚合类型,因此它具有空的初始化.因此,只有第一颗子弹适用.然而,这显然不是在获得存储时,因此不能在其寿命开始时.
分配器需要在不构造其元素的情况下返回内存.然而,这对于琐碎的类型来说没有意义.的影响a.allocate(n)与a对类型的分配器对象T是
n为类型的T对象分配内存,但不构造对象.
我知道用C编码,函数的返回值使用%eax寄存器返回给调用者.
使用c ++,也可以返回结构而不仅仅是'Primitive'类型,所以当一个函数返回一个结构时,存储的返回值在哪里(堆栈,堆等)?
示例代码:
class Student
{
private:
int m_id;
public:
Student(int id)
{
m_id = id;
};
~Student();
int getId()
{
return m_id;
};
};
Student myFunc()
{
return Student(123);
}
int main()
{
//How does 'student1' get the value from the function?
//Does 'myFunc' write directly to the stack of main?
Student student1 = myFunc();
return 0;
}
Run Code Online (Sandbox Code Playgroud) 从gcc的文档来看
如果控制流程到达该点
__builtin_unreachable,则程序未定义.
我认为__builtin_unreachable可以用各种创造性的方式暗示优化器.所以我做了一个小实验
void stdswap(int& x, int& y)
{
std::swap(x, y);
}
void brswap(int& x, int& y)
{
if(&x == &y)
__builtin_unreachable();
x ^= y;
y ^= x;
x ^= y;
}
void rswap(int& __restrict x, int& __restrict y)
{
x ^= y;
y ^= x;
x ^= y;
}
Run Code Online (Sandbox Code Playgroud)
被编译为(g ++ -O2)
stdswap(int&, int&):
mov eax, DWORD PTR [rdi]
mov edx, DWORD PTR [rsi]
mov DWORD PTR [rdi], edx
mov DWORD PTR [rsi], eax …Run Code Online (Sandbox Code Playgroud) 问题如标题中所述,该函数可能会被重载或模板化,并且必须在块范围内完成。这是我最好的,但是在函数引用上失败了
#include <type_traits>
template <typename... Fs> struct overload : Fs... {
using Fs::operator()...;
std::true_type operator()(...);
};
#define is_funcname(f) \
[] { \
auto l = [](auto x) mutable \
-> std::bool_constant<!std::is_pointer_v<decltype(x, f)>> { \
return {}; \
}; \
auto o = overload<decltype(l)>{}; \
return decltype(o(42))::value; \
}()
void bar() {}
void bar(int) {}
void baz() {}
void foo() {
static_assert(is_funcname(bar));
static_assert(!is_funcname((void (*)())bar));
static_assert(is_funcname(baz));
static_assert(!is_funcname(+baz));
auto &r = baz;
static_assert(!is_funcname(r)); // fails
}
Run Code Online (Sandbox Code Playgroud)
用例是我的库必须决定是否需要将表达式捕获为类型已擦除的上下文,在某些平台上可能不支持这种情况,应避免使用。
我目前正在研究 OCR(波斯语),尽管 tessdata 中提供了“fas.traineddata”,但是当我使用以下命令时,没有任何反应:
import pytesseract
from PIL import Image
print(pytesseract.image_to_string(Image.open('image.png'), lang='fas'))
Run Code Online (Sandbox Code Playgroud)
图像:

我还使用了https://github.com/reza1615/PersianOcr的训练数据,但再次没有结果。
我应该怎么办?
谢谢
是否有关于如何解决歧义语法的一般规则?
特别是,伪析构函数名称包括这些产生规则
嵌套名称说明符opt类型名称 :: ~ 类型名称
嵌套名称说明符opt ~ 类型名称
嵌套名称说明符包括
嵌套名称说明符标识符 ::
类型名称 ::
鉴于以下情况
struct A
{
struct B {};
B b;
};
A a;
a.b.A::B::~B();
Run Code Online (Sandbox Code Playgroud)
最后一条生产线选择以下哪一种产品?
类型名称 :: 类型名称 :: ~ 类型名称
类型名称 :: 标识符 :: ~ 类型名称
这在模板化上下文中具有重要意义,因为[temp.res]
在立即包含依赖于模板参数的嵌套名称说明符的嵌套名称说明符中,隐式假定标识符或 simple-template-id 来命名类型,而不使用 typename 关键字。
c++ ×9
c ×1
c++14 ×1
gcc ×1
interface ×1
lambda ×1
object-model ×1
ocr ×1
optimization ×1
type-traits ×1