元编程总结

编译期算结果C98示例:

1
2
3
4
5
6
7
template <int n> struct fact98 {
 static const int value = n * fact98<n - 1>::value;
};
template <> struct fact98<0> {
 static const int value = 1;
};
std::cout << fact98<5>::value << std::endl;

或C11的示例:

1
2
3
constexpr int fact11(int n) {
 return n <= 1 ? 1 : (n * fact11(n - 1));
}

C11中不能使用变量和循环,C14中可以:

1
2
3
4
5
constexpr int fact14(int n) {
 int s = 1;
 for (int i = 1; i <= n; i++) { s = s * i; }
 return s;
}

编译期检查1:

1
2
3
4
5
6
7
static_assert(sizeof(void *) == 8, "expected 64-bit platform");
 
template<typename T, int Row, int Column>
struct Matrix {
 static_assert(Row >= 0, "Row number must be positive.");
 static_assert(Column >= 0, "Column number must be positive.");
};

编译期检查2:

1
2
3
4
5
6
7
8
9
struct A {
void foo(){}
 int member;
};
template<typename Function>
std::enable_if_t<!std::is_member_function_pointer_v<Function>> foo(Function&& f) {
}
foo([] {}); //ok
foo(&A::foo); //compile error: no matching function for call to 'foo(void (A::*)())'

编译期检查3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template< class, class = void >
struct has_foo : std::false_type {};
template< class T >
struct has_foo< T, std::void_t<decltype(std::declval<T>().foo())> > : std::true_type {};
template< class, class = void >
struct has_member : std::false_type {};
template< class T >
struct has_member< T, std::void_t<decltype(std::declval<T>().member)> > : std::true_type {};
struct A {
 void foo(){}
 int member;
};
static_assert(has_foo< A >::value);
static_assert(has_member< A >::value);

refer to: https://www.toutiao.com/a6646250452335723021/

win32将当前目录切换到程序所在目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int pathGetContainer(const char *path, string &dir)
{
	const char *p;
	for (p = path + strlen(path); p >= path; p--)
	{
		if (*p == '/' || *p == '\\')
			break;
	}
	dir = string(path).substr(0, p - path + 1);
	return 1;
}
 
...
	char curPath[1024];
	GetModuleFileNameA(AfxGetApp()->m_hInstance, curPath, sizeof(curPath));
	string curDir;
	pathGetContainer(curPath, curDir);
	SetCurrentDirectoryA(curDir.c_str());
...

注:此方法对于Windows shell编程不适用,因为是运行在资源管理器进程里的插件,返回的都是explorer.exe所在路径,此种情况下,一般是通过注册表里写死的配置获取进程路径。

DeleteFile 5 unlink EACCES

查了很多网页,有的说是要删除的文件存在打开的句柄未关掉。而我这种情况是在程序一开始DeleteFile删除某个文件就删不掉,报ERROR_ACCESS_DENIED的错,换成_unlink删也删不掉。

但我在同样的目录新建一个文本文件再DeleteFile此文本文件是可以删除的。

于是我怀疑是不是有钩子进程使坏,我将“QQ电脑管家”程序退出,结果就可以成功调用DeleteFile了。

也就是说,“QQ电脑管家”阻止了DeleteFile删除某些特定后缀的文件,比如jpg后缀的文件。

printf Stack overflow

可能原因是栈空间用光了,需要仔细检查上下文中,看有没有存在占很大空间的局部变量。有的话,改为堆上分配这些变量。

读取jpg文件到HBITMAP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
HBITMAP loadPictureFromFile(LPCTSTR szFile)
{
	HANDLE hFile = CreateFile(szFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (INVALID_HANDLE_VALUE == hFile)
		return NULL;
 
	DWORD dwFileSize = GetFileSize(hFile, NULL);
 
	LPVOID pvData = NULL;
	HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
 
	pvData = GlobalLock(hGlobal);
 
	DWORD dwBytesRead = 0;
	BOOL bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL);
	GlobalUnlock(hGlobal);
	CloseHandle(hFile);
 
	LPSTREAM pStm = NULL;
	HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
 
	LPPICTURE gpPicture;
 
	hr = ::OleLoadPicture(pStm, dwFileSize, FALSE, IID_IPicture, (LPVOID *)&gpPicture);
 
	pStm->Release();
 
	OLE_HANDLE picHandle;
	gpPicture->get_Handle(&picHandle);
	HDC hdc = ::CreateCompatibleDC(NULL);
	::SelectObject(hdc, (HGDIOBJ)picHandle);
 
	HBITMAP hRet = (HBITMAP)::GetCurrentObject(hdc, OBJ_BITMAP);
	DeleteDC(hdc);
 
//	gpPicture->Release(); // 这里不能释放gpPicture,否则返回的hRet是野指针数据
 
	return hRet;
}

MFC CScrollBar拖动完后总跑到零位置

原因是

  1. 要处理SB_ENDSCROLL事件。
  2. 一定要在适当的地方GetScrollPos或SetScrollPos。

正确示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void SampleDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	int iMin = 0, iMax = 0;
	pScrollBar->GetScrollRange(&iMin, &iMax);
 
	// nPos = pScrollBar->GetScrollPos(); // 此处这句话一定不能有
 
	switch (nSBCode)
	{
	case SB_THUMBTRACK:
		break;
	case SB_LINELEFT:
		nPos = pScrollBar->GetScrollPos(); // 此处这句话一定要有
		nPos--;
		if (nPos < (UINT)iMin)
			nPos = 0;
		break;
	case SB_LINERIGHT:
		nPos = pScrollBar->GetScrollPos(); // 此处这句话一定要有
		nPos++;
		if (nPos >= (UINT)iMax)
			nPos = iMax - 1;
		break;
	case SB_ENDSCROLL:
		nPos = pScrollBar->GetScrollPos(); // 此处这句话一定要有
		break;
	default:
		break;
	}
 
	pScrollBar->SetScrollPos(nPos, 1); // 此处这句话也一定要有
 
	// Todo real work with nPos.
 
	CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

error C4839: 作为可变参数函数的参数的非标准用法

报错语句为:

1
	_stprintf_s(filepath, _T("%s\\%s"), curpath, CA2T(iniFilePath));

改为如下就不报错了:

1
2
	CString iniFilePathT = CA2T(iniFilePath);
	_stprintf_s(filepath, _T("%s\\%s"), curpath, (LPCTSTR)iniFilePathT);

targetSdkVersion未安装应用程式

发布后在Android 6.1的手机上安装不了,显示“未安装应用程序”,检查源码发现build.gradle文件中

1
2
3
4
    defaultConfig {
        minSdkVersion 14
	targetSdkVersion 27
    }

于是,把targetSdkVersion改为23,而发布release版时,Signature Versions只选V1(Jar Signature)。
再将生成的apk包在安卓6.1手机上装,顺利安装成功。