C++在 Visual Studio 2005 上使用 TCHAR 进行模板函数专业化
我正在编写一个使用模板化运算符<<的日志记录类功能。我将模板函数专门用于宽字符字符串,以便在编写日志消息之前可以进行一些从宽到窄的转换。我无法让 TCHAR 正常工作 - 它不使用专业化。有想法吗?
下面是相关代码:
// Log.h header
class Log
{
public:
template <typename T> Log& operator<<( const T& x );
template <typename T> Log& operator<<( const T* x );
template <typename T> Log& operator<<( const T*& x );
...
}
template <typename T> Log& Log::operator<<( const T& input )
{ printf("ref"); }
template <typename T> Log& Log::operator<<( const T* input )
{ printf("ptr"); }
template <> Log& Log::operator<<( const std::wstring& input );
template <> Log& Log::operator<<( const wchar_t* input );
和源文件
// Log.cpp
template <> Log& Log::operator<<( const std::wstring& input )
{ printf("wstring ref"); }
template <> Log& Log::operator<<( const wchar_t* input )
{ printf("wchar_t ptr"); }
template <> Log& Log::operator<<( const TCHAR*& input )
{ printf("tchar ptr ref"); }
现在,我使用以下测试程序来练习这些功能
// main.cpp - test program
int main()
{
Log log;
log << "test 1";
log << L"test 2";
std::string test3( "test3" );
log << test3;
std::wstring test4( L"test4" );
log << test4;
TCHAR* test5 = L"test5";
log << test5;
}
运行上述测试会显示以下内容:
// Test results
ptr
wchar_t ptr
ref
wstring ref
ref
不幸的是,这并不完全正确。我真的希望最后一个是“TCHAR”,这样我就可以转换它。根据 Visual Studio 的调试器,当我进入测试 5 中调用的函数时,类型为 wchar_t*& - 但它没有调用适当的专业化。有想法吗?
我不确定它是否相关,但这是在 Windows CE 5.0 设备上。
I'm writing a logging class that uses a templatized operator<< function. I'm specializing the template function on wide-character string so that I can do some wide-to-narrow translation before writing the log message. I can't get TCHAR to work properly - it doesn't use the specialization. Ideas?
Here's the pertinent code:
// Log.h header
class Log
{
public:
template <typename T> Log& operator<<( const T& x );
template <typename T> Log& operator<<( const T* x );
template <typename T> Log& operator<<( const T*& x );
...
}
template <typename T> Log& Log::operator<<( const T& input )
{ printf("ref"); }
template <typename T> Log& Log::operator<<( const T* input )
{ printf("ptr"); }
template <> Log& Log::operator<<( const std::wstring& input );
template <> Log& Log::operator<<( const wchar_t* input );
And the source file
// Log.cpp
template <> Log& Log::operator<<( const std::wstring& input )
{ printf("wstring ref"); }
template <> Log& Log::operator<<( const wchar_t* input )
{ printf("wchar_t ptr"); }
template <> Log& Log::operator<<( const TCHAR*& input )
{ printf("tchar ptr ref"); }
Now, I use the following test program to exercise these functions
// main.cpp - test program
int main()
{
Log log;
log << "test 1";
log << L"test 2";
std::string test3( "test3" );
log << test3;
std::wstring test4( L"test4" );
log << test4;
TCHAR* test5 = L"test5";
log << test5;
}
Running the above tests reveals the following:
// Test results
ptr
wchar_t ptr
ref
wstring ref
ref
Unfortunately, that's not quite right. I'd really like the last one to be "TCHAR", so that I can convert it. According to Visual Studio's debugger, the when I step in to the function being called in test 5, the type is wchar_t*& - but it's not calling the appropriate specialization. Ideas?
I'm not sure if it's pertinent or not, but this is on a Windows CE 5.0 device.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
TCHAR 是一个引用 wchar_t 或 char 的 typedef 的宏。当您实例化模板时,宏已被替换。您最终将引用 char 的模板实例或 wchar_t 的模板实例。
TCHAR is a macro that references a typedef either for wchar_t or for char. By the time you're instantiating templates, the macro has already been substituted. You're going to end up referencing either your template instance for char or the one for wchar_t.
(@jwismar 所说的是正确的,但这不是代码的主要问题)。
考虑这段代码,
如果您尝试编译它,将会导致错误。错误的原因是无法将
const int *&
类型的引用绑定到int *
类型的指针。这将违反常量正确性规则。另一个较小的示例说明了相同的问题
这实际上也是您的代码中存在的问题。您使用 const TCHAR*& 参数类型声明了模板
,并期望为
TCHAR *
类型的参数调用它,这是不可能的。您的模板不被视为该调用的可行函数。将
const
添加到参数类型,或从参数类型中删除const
。或者,也许,摆脱参考。 (为什么将参数声明为指针的引用?)调用模板而不是您想要的目标函数
PS您可能会感到惊讶,编译器首先 看起来编译器似乎正在做我刚才所说的“不可能”的事情。实际上,编译器正在做的是完全不同的事情。
后一个模板使用等于
TCHAR *
的T
进行实例化。如果您仔细展开上述T == TCHAR *
的参数声明,您将得到TCHAR *const &
,而不是const TCHAR *&
。这是两个完全不同的事情。完全可以使用TCHAR *
指针初始化TCHAR *const &
引用,这正是编译器在您的情况下所做的事情。回到我的简单例子
(What @jwismar says is correct, but that is not the main problem with the code).
Consider this piece of code
If you try to compile it, it will result in an error. The reason for the error is that it is impossible to bind a reference of
const int *&
type to a pointer ofint *
type. This would violate the const-correctness rules.Another, smaller example that illustrates the same problem
This is actually the problem you have in your code as well. You declared your template with
const TCHAR*&
parameter typeand expect it to be called for argument of
TCHAR *
typeIt is impossible. Your template is not considered as a viable function for the call. Either add
const
to the argument type, or removeconst
from the parameter type. Or, maybe, get rid of the reference. (Why do you declare the parameter as a reference to a pointer?)P.S. You might find it surprising that instead of your desired target function the compiler calls the template
At the first sight it might seem as if the compiler is doing what I just called "impossible". In reality, what the compiler is doing is a completely different thing.
The latter template gets instantiated with
T
equal toTCHAR *
. How, if you carefully expand the above argument declaration forT == TCHAR *
, you'll getTCHAR *const &
, notconst TCHAR *&
. These are two completely different things. It is perfectly possible to initialize aTCHAR *const &
reference with aTCHAR *
pointer, which is exactly what the compiler is doing in your case.Returning to my simple example
啊哈!
因此,我将问题分解为最小的部分,并发现了一些有关模板函数匹配顺序的信息。首先,我将程序分解为
:
// Log.h
和
// Log.ccp
果然,我的模板专业化被调用了。当我像这样向 Log 标头添加另一个专门化时,
编译器开始匹配新函数。然而,这一次我没有包含模板的定义,因此链接器抱怨。链接器显示以下错误:
这告诉我它试图匹配的类型:
const指针,而不是指向const引用的指针!所以,现在我的程序可以运行了。我只是像这样专门化模板:
感谢大家的帮助。
A-HA!
So, I broke the problem down into it's smallest part and discovered something about the order in which template functions are matched. First, I broke the program down into this:
And
// Log.h
And
// Log.ccp
And sure enough, my template specialization got called. When I added another specialization to the Log header like this
The compiler started matching the new function instead. This time, however, I didn't include a definition for the template, so the linker complained. The linker showed the following error:
This told me the type it was trying to match:
A const pointer, not a pointer-to-const reference! So, now my program works. I just specialize the template like so:
Thanks for the help everyone.
我认为缺乏常量会让编译器感到困惑。
尝试
或更正确地
我认为这会给你你所期望的。
I think that the lack of constness is confusing the compiler.
Try
or even more correctly
I think that will give you what you expect.