将函数传递给模板
Passing a function to a template
我正在为我正在处理的应用程序编写一个 Win32Exception,头文件如下所示:
class Win32Exception : std::exception {
public:
Win32Exception() = default;
explicit Win32Exception(const std::wstring& message);
explicit Win32Exception(const std::string& message);
explicit Win32Exception(const char* message);
virtual ~Win32Exception() throw() override = default;
char const* what() const override;
std::wstring message() const;
};
what
函数的实现如下所示:
char const* Win32Exception::what() const
{
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
LPSTR buffer = nullptr;
DWORD length = FormatMessageA(flags, nullptr, errorCode, systemLocale, (LPSTR)&buffer, 0, nullptr);
if(buffer != nullptr)
{
LocalFree(buffer);
}
else if (length == 0)
{
buffer = "Cannot get an error message. FormatMessage failed.";
}
return buffer;
}
message
函数的实现如下所示:
std::wstring Win32Exception::message() const
{
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
LPWSTR buffer = nullptr;
DWORD length = FormatMessageW(flags, nullptr, errorCode, systemLocale, (LPWSTR)&buffer, 0, nullptr);
if (buffer != nullptr)
{
LocalFree(buffer);
}
else if (length == 0)
{
buffer = L"Cannot get an error message. FormatMessage failed.";
}
return buffer;
}
现在,我想摆脱这种重复,所以我想我可以用模板做一些事情,如下所示:
template <typename TResult, DWORD (*formatMessageVersion)(DWORD, LPCVOID, DWORD, DWORD, TResult, DWORD, va_list*)>
TResult formatMessage(DWORD& systemLocale, DWORD& errorCode, TResult& fallbackMessage) const {
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
TResult buffer = nullptr;
DWORD length = formatMessageVersion(flags, nullptr, errorCode, systemLocale, (TResult)&buffer, 0, nullptr);
if (buffer != nullptr)
{
LocalFree(buffer);
}
else if (length == 0)
{
buffer = fallbackMessage;
}
return buffer;
}
在我的一次尝试中,我试图将函数FormatMessageA/W
作为formatMessage
参数传递给 std::function,但我不确定为什么它不起作用......
我认为我使用它的方式如下:
char const* Win32Exception::what() const
{
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
return formatMessage<LPSTR, FormatMessageA>(systemLocale,
errorCode,
"Cannot get an error message. FormatMessage failed.");
}
std::wstring Win32Exception::message() const
{
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
return formatMessage<LPWSTR, FormatMessageW>(systemLocale,
errorCode,
L"Cannot get an error message. FormatMessage failed.");
}
但是我收到一堆错误:
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPSTR,DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const char [51]' to 'LPSTR &' RunBox d:userseyalprojectscodeyallacoresrcrunboxwin32win32-exception.cpp 29
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPSTR,DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const char [51]' to 'LPSTR &' RunBox d:userseyalprojectscodeyallacoresrcrunboxwin32win32-exception.cpp 29
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPWSTR,DWORD FormatMessageW(DWORD,LPCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const wchar_t [51]' to 'LPWSTR &' RunBox d:userseyalprojectscodeyallacoresrcrunboxwin32win32-exception.cpp 40
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPWSTR,DWORD FormatMessageW(DWORD,LPCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const wchar_t [51]' to 'LPWSTR &' RunBox d:userseyalprojectscodeyallacoresrcrunboxwin32win32-exception.cpp 40
Severity Code Description Project File Line Suppression State
Error (active) no instance of function template "Yalla::Win32Exception::formatMessage" matches the argument list RunBox d:UsersEyalProjectsCodeYallacoresrcrunboxwin32win32-exception.cpp 27
Severity Code Description Project File Line Suppression State
Error (active) no instance of function template "Yalla::Win32Exception::formatMessage" matches the argument list RunBox d:UsersEyalProjectsCodeYallacoresrcrunboxwin32win32-exception.cpp 38
请记住,我正在重新学习C++并且多年来没有碰过它,所以如果您能告诉我如何改进代码或以更好的方式做任何我试图做的事情,我真的很高兴听到它! ;)
更新:您可以在GitHub上找到最终的解决方案,感谢大家。
不要通过模板解决重复问题。您已经有一个函数 message()
,用于调用FormatMessageW
并获取消息文本。这就是您所需要的。若要实现what()
需要一个 ANSI 字符串。因此,请先调用message()
然后转换为ANSI。
换句话说,通过首先调用 message()
来实现what()
。然后将std::wstring
转换为std::string
。然后返回c_str()
产生的const char*
。不过,您需要将std::string
存储在成员字段中,以便c_str
返回的指针保持有效。
要执行转换,请参阅此处显示的有关该主题的众多问题之一。例如:如何将 wstring 转换为字符串?
就目前而言,您当前的 what()
实现返回一个无效的指针,因为它对随后返回的值调用LocalFree
。但是,如果您遵循我的建议,所有这些代码都会消失,所以不要太纠结于此。
您对FormatMessageW
的错误处理是错误的。成功或其他方面由返回值指示,如文档所示。值为 0
表示失败。这就是您需要测试的内容。我怎么强调都不够强调非常仔细地阅读文档的重要性。我想说的是,我们在这里看到的>90% 的 winapi 问题在错误处理中都有错误。
更重要的是,在释放buffer
后,您将再次访问它。代码应该更像这样:
LPWSTR buffer;
DWORD length = FormatMessageW(flags, nullptr, errorCode, systemLocale, (LPWSTR)&buffer,
0, nullptr);
if (length == 0)
return L"Cannot get an error message. FormatMessage failed.";
std::wstring retval = buffer;
LocalFree(buffer);
return retval;
您应该允许向类传递错误代码。一些错误代码由 API 直接返回,例如注册表 API。此外,在您设法获得调用GetLastError
的代码之前,您有时会对SetLastError
运行时调用C++感到困惑。
直接问题在此处的错误消息中描述:
[...] cannot convert argument 3 from 'const char [51]' to 'LPSTR &' [...]
您正在将字符文本传递给需要非常量引用的函数。您不能将非常量引用绑定到临时引用,因此简单的解决方法只是将最后一个参数类型从 TResult&
更改为 TResult const&
。这应该可以解决您的问题。
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗