Специализация шаблонной функции C ++ с использованием TCHAR в Visual Studio 2005 - PullRequest
0 голосов
/ 12 июня 2010

Я пишу класс журналирования, который использует шаблонную функцию operator <<. Я специализирую функцию шаблона на широкой символьной строке, чтобы я мог выполнить перевод с широкой на узкую область перед написанием сообщения журнала. Я не могу заставить TCHAR работать должным образом - он не использует специализацию. Идеи? </p>

Вот соответствующий код:

// 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.

Ответы [ 4 ]

5 голосов
/ 12 июня 2010

TCHAR - это макрос, который ссылается на typedef либо для wchar_t, либо для char.К тому времени, когда вы создаете экземпляры шаблонов, макрос уже заменен.В конечном итоге вы будете ссылаться либо на свой экземпляр шаблона для char, либо на wchar_t.

1 голос
/ 12 июня 2010

(То, что @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 из типа параметра.Или, может быть, избавиться от ссылки.(Почему вы объявляете параметр как ссылка на указатель?)

PS Может показаться удивительным, что вместо желаемой целевой функции компилятор вызываетtemplate

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

На первый взгляд может показаться, что компилятор делает то, что я только что назвал "невозможным".На самом деле то, что делает компилятор, это совсем другое.

Последний шаблон создается с T, равным TCHAR *.Как, если вы аккуратно развернете приведенное выше объявление аргумента для T == TCHAR *, вы получите TCHAR *const &, а не const TCHAR *&.Это две совершенно разные вещи.Вполне возможно инициализировать ссылку TCHAR *const & указателем TCHAR *, что в точности и делает компилятор в вашем случае.

Возвращаясь к моему простому примеру

int *p = 0;
const int *&rp1 = p; // ERROR: cannot initialize `const int *&` with `int *`
int *const &rp2 = p; // OK, no error here
0 голосов
/ 12 июня 2010

Я думаю, что отсутствие константности сбивает с толку компилятор.

Попробуйте

        const TCHAR* test5 = L"test5";

или даже правильнее

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

Я думаю, что это даст вамчто вы ожидаете.

0 голосов
/ 12 июня 2010

A-HA!

Итак, я разбил проблему на ее наименьшую часть и обнаружил кое-что о порядке, в котором сопоставляются функции шаблона. Сначала я разбил программу на это:

// 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; }

И, конечно же, моя специализация по шаблону получила название. Когда я добавил другую специализацию в заголовок журнала, как это

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 &

A const указатель, а не ссылка на указатель на const! Итак, теперь моя программа работает. Я просто специализирую шаблон так:

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

Спасибо за помощь всем.

...