Компилятор выбирает неправильную специализацию шаблонной функции - PullRequest
3 голосов
/ 21 июня 2011

Я отчаянно пытаюсь заставить мои специализации работать, но у меня все еще есть не компилируемый код из-за неправильного вывода аргументов.Обратите внимание, что ошибки связаны не с определением шаблонов, а с применением несоответствующей операции в неправильной реализации шаблона.Сокращенный пример кода, демонстрирующего проблему:

struct Test { void Method() const {} };

template<typename T>
void Cmp(T _val) { _val > 1; }

template<>
void Cmp<const Test &>(const Test &_val) { _val.Method(); }

template<>
void Cmp<const char *>(const char *_val) { _val[2]; }

int main()
{
  Test test1;
  char test2[5];

  Cmp(10);    // ok, expected
  Cmp(test1); // error in Cmp(T)?! but expecting to instantiate Cmp(const Test &)
  Cmp(test2); // error in Cmp(T)?! but expecting to instantiate Cmp(const char *)
  return 0;
}

Я действительно не хочу использовать явные вызовы, такие как Cmp<const Test &>(test1) (это работает), поскольку AFAIK компилятор должен иметь возможность выводить аргументыавтоматически, и вся идея этих специализаций заключается в прозрачной диспетчеризации вызовов Cmp (в реальном коде я определяю операторы).Конечно, специализация по стоимости Cmp<Test>(Test) работает, как и ожидалось, но для большого сложного класса, не являющегося POD, просто смешно передавать его по значению.специализация по ссылкам с использованием общего шаблона.Кажется, я упускаю что-то важное, но у меня действительно заканчиваются идеи, почему мой подход не работает и как я должен конструировать код, выражающий такую ​​простую концепцию из мира без шаблонов C ++, как передача классов по ссылке.Конечно, Google оказался совершенно бесполезным для этой проблемы.^ _ ^ Я пробовал GCC 4.2.1 и 4.4.6.

Ответы [ 2 ]

12 голосов
/ 21 июня 2011
Cmp(test1);

Здесь T выводится из аргумента Test. Он не выводится как const Test&, поэтому ваша специализация не совпадает, поэтому и создается первичный шаблон. Вы должны будете заставить свою специализацию принимать Test по значению. В этом объявлении действительно используется специализация:

template<>
void Cmp<Test>(Test _val) { _val.Method(); }

Cmp(test1);

Здесь T определяется как char*, а не const char*, поэтому специализация не совпадает. Вам нужно будет специализироваться на char* вместо const char*, чтобы соответствовать этому. Кроме того, вы можете преобразовать аргумент в const char* при выполнении вызова:

const char* test2ptr = test2;
Cmp(test2ptr); 

Все это говорит, зачем вообще специализироваться, когда можно перегрузить?

template<typename T>
void Cmp(T _val) { _val > 1; }

void Cmp(const Test &_val) { _val.Method(); }

void Cmp(const char *_val) { _val[2]; }

// Add an overload to support arrays of char:
template <unsigned N>
void Cmp(const char (&_val)[N]) { _val[1]; }

Вам действительно следует избегать специализированных шаблонов функций. Это сложно и в большинстве случаев просто не стоит проблем.

4 голосов
/ 21 июня 2011

Эмм ... зачем специализироваться?Просто перегрузите его ..

void Cmp(const Test &_val) { _val.Method(); }

void Cmp(const char *_val) { _val[2]; }

100% гарантия выбора этих методов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...