C++在 Visual Studio 2005 上使用 TCHAR 进行模板函数专业化

发布于 2024-09-05 07:16:48 字数 1735 浏览 15 评论 0原文

我正在编写一个使用模板化运算符<<的日志记录类功能。我将模板函数专门用于宽字符字符串,以便在编写日志消息之前可以进行一些从宽到窄的转换。我无法让 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

以歌曲疗慰 2024-09-12 07:16:48

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.

棒棒糖 2024-09-12 07:16:48

(@jwismar 所说的是正确的,但这不是代码的主要问题)。

考虑这段代码,

void foo(const int*& p);

int main() {
  int *p = 0;
  foo(p); // ERROR: cannot initialize `const int *&` with `int *`
}

如果您尝试编译它,将会导致错误。错误的原因是无法将const int *&类型的引用绑定到int *类型的指针。这将违反常量正确性规则。

另一个较小的示例说明了相同的问题

int *p = 0;
const int *&rp = p; // ERROR: cannot initialize `const int *&` with `int *`

这实际上也是您的代码中存在的问题。您使用 const TCHAR*& 参数类型声明了模板

template <> Log& Log::operator<<( const TCHAR*& input )
{ printf("tchar ptr ref"); }

,并期望为 TCHAR * 类型的参数调用它,

TCHAR* test5 = L"test5";
log << test5;

这是不可能的。您的模板不被视为该调用的可行函数。将 const 添加到参数类型,或从参数类型中删除 const。或者,也许,摆脱参考。 (为什么将参数声明为指针的引用?)

调用模板而不是您想要的目标函数

template <typename T> Log& Log::operator<<( const T& input )
{ printf("ref"); }

PS您可能会感到惊讶,编译器首先 看起来编译器似乎正在做我刚才所说的“不可能”的事情。实际上,编译器正在做的是完全不同的事情。

后一个模板使用等于 TCHAR *T 进行实例化。如果您仔细展开上述 T == TCHAR * 的参数声明,您将得到 TCHAR *const &,而不是 const TCHAR *&。这是两个完全不同的事情。完全可以使用 TCHAR * 指针初始化 TCHAR *const & 引用,这正是编译器在您的情况下所做的事情。

回到我的简单例子

int *p = 0;
const int *&rp1 = p; // ERROR: cannot initialize `const int *&` with `int *`
int *const &rp2 = p; // OK, no error here

(What @jwismar says is correct, but that is not the main problem with the code).

Consider this piece of code

void foo(const int*& p);

int main() {
  int *p = 0;
  foo(p); // ERROR: cannot initialize `const int *&` with `int *`
}

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 of int * type. This would violate the const-correctness rules.

Another, smaller example that illustrates the same problem

int *p = 0;
const int *&rp = p; // ERROR: cannot initialize `const int *&` with `int *`

This is actually the problem you have in your code as well. You declared your template with const TCHAR*& parameter type

template <> Log& Log::operator<<( const TCHAR*& input )
{ printf("tchar ptr ref"); }

and expect it to be called for argument of TCHAR * type

TCHAR* test5 = L"test5";
log << test5;

It is impossible. Your template is not considered as a viable function for the call. Either add const to the argument type, or remove const 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

template <typename T> Log& Log::operator<<( const T& input )
{ printf("ref"); }

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 to TCHAR *. How, if you carefully expand the above argument declaration for T == TCHAR *, you'll get TCHAR *const &, not const TCHAR *&. These are two completely different things. It is perfectly possible to initialize a TCHAR *const & reference with a TCHAR * pointer, which is exactly what the compiler is doing in your case.

Returning to my simple example

int *p = 0;
const int *&rp1 = p; // ERROR: cannot initialize `const int *&` with `int *`
int *const &rp2 = p; // OK, no error here
画▽骨i 2024-09-12 07:16:48

啊哈!

因此,我将问题分解为最小的部分,并发现了一些有关模板函数匹配顺序的信息。首先,我将程序分解为

// main.cpp
int main()
{
 Log log;
 wchar_t* test = L"test";
 log << test;
 return 0;
}


// Log.h

class Log
{
  public:
   template <typename T> Log& operator<<( const T* x );
};

template <> Log& Log::operator<<( wchar_t* const & input );


// Log.ccp

#include "Log.h"

template <> Log& Log::operator<<( const wchar_t* input )
{ printf("wchar_t ptr\n"); return *this; }

果然,我的模板专业化被调用了。当我像这样向 Log 标头添加另一个专门化时,

template <typename T> Log& operator<<( const T& x );

编译器开始匹配新函数。然而,这一次我没有包含模板的定义,因此链接器抱怨。链接器显示以下错误:

error LNK2019: unresolved external symbol "public: class Log & __thiscall Log::operator<<<wchar_t *>(wchar_t * const &)" (??$?6PA_W@Log@@QAEAAV0@ABQA_W@Z) referenced in function _main

这告诉我它试图匹配的类型:

wchar_t* const &

const指针,而不是指向const引用的指针!所以,现在我的程序可以运行了。我只是像这样专门化模板:

template <> Log& Log::operator<<( wchar_t* const & input );

感谢大家的帮助。

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:

// main.cpp
int main()
{
 Log log;
 wchar_t* test = L"test";
 log << test;
 return 0;
}

And
// Log.h

class Log
{
  public:
   template <typename T> Log& operator<<( const T* x );
};

template <> Log& Log::operator<<( wchar_t* const & input );

And
// Log.ccp

#include "Log.h"

template <> Log& Log::operator<<( const wchar_t* input )
{ printf("wchar_t ptr\n"); return *this; }

And sure enough, my template specialization got called. When I added another specialization to the Log header like this

template <typename T> Log& operator<<( const T& x );

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:

error LNK2019: unresolved external symbol "public: class Log & __thiscall Log::operator<<<wchar_t *>(wchar_t * const &)" (??$?6PA_W@Log@@QAEAAV0@ABQA_W@Z) referenced in function _main

This told me the type it was trying to match:

wchar_t* const &

A const pointer, not a pointer-to-const reference! So, now my program works. I just specialize the template like so:

template <> Log& Log::operator<<( wchar_t* const & input );

Thanks for the help everyone.

笑看君怀她人 2024-09-12 07:16:48

我认为缺乏常量会让编译器感到困惑。

尝试

        const TCHAR* test5 = L"test5";

或更正确地

        const TCHAR* test5 = _T("test5");

我认为这会给你你所期望的。

I think that the lack of constness is confusing the compiler.

Try

        const TCHAR* test5 = L"test5";

or even more correctly

        const TCHAR* test5 = _T("test5");

I think that will give you what you expect.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文