Especialização em modelos VS Sobrecarga de funções

Um livro que eu tenho notas que você pode fornecer sua própria implementação para funções de biblioteca padrão como swap(x,y) através de especialização de modelo para sobrecarga de function. Isso seria útil para todos os tipos que podem se beneficiar de algo diferente de uma troca de atribuição, como, por exemplo, STL containers (que já possuem swaps escritos, eu sei).

Minhas perguntas são:

  1. O que é melhor: especialização de modelo para fornecer sua implementação de troca especializada ou sobrecarga de function fornecendo os parâmetros exatos que você deseja usar sem um modelo?

  2. Por que isso é melhor? Ou se eles são iguais, porque é isso?

Breve história: sobrecarga quando você puder, se especializar quando precisar.

Longa história: C ++ trata a especialização e sobrecarrega de maneira muito diferente. Isso é melhor explicado com um exemplo.

 template  void foo(T); template  void foo(T*); // overload of foo(T) template <> void foo(int*); // specialisation of foo(T*) foo(new int); // calls foo(int*); 

Agora vamos trocar os dois últimos.

 template  void foo(T); template <> void foo(int*); // specialisation of foo(T) template  void foo(T*); // overload of foo(T) foo(new int); // calls foo(T*) !!! 

O compilador faz a resolução de sobrecarga antes mesmo de analisar as especializações. Portanto, em ambos os casos, a resolução de sobrecarga escolhe foo(T*) . No entanto, somente no primeiro caso ele encontra foo(int*) porque no segundo caso a especialização int* é uma especialização de foo(T) , não foo(T*) .


Você mencionou std::swap . Isso torna as coisas ainda mais complicadas.

O padrão diz que você pode adicionar especializações ao namespace std . Ótimo, então você tem algum tipo Foo e ele tem uma troca de desempenho, então você apenas especializa swap(Foo&, Foo&) no namespace std . Sem problemas.

Mas e se Foo for uma class de modelo? O C ++ não possui especialização parcial de funções, portanto você não pode especializar-se em swap . Sua única opção é sobrecarregar, mas o padrão diz que você não tem permissão para adicionar sobrecargas no namespace std !

Você tem duas opções neste momento:

  1. Crie uma function swap(Foo&, Foo&) no seu próprio namespace, e espere que ela seja encontrada via ADL. Eu digo “esperança” porque se a biblioteca padrão chamar swap como std::swap(a, b); então o ADL simplesmente não funcionará.

  2. Ignore a parte do padrão que diz não para adicionar sobrecargas e fazê-lo de qualquer maneira. Honestamente, mesmo que tecnicamente não seja permitido, em todos os cenários realistas isso vai funcionar.

Uma coisa a ser lembrada é que não há garantia de que a biblioteca padrão use swap . A maioria dos algoritmos usa std::iter_swap e em algumas implementações que eu observei, ele nem sempre encaminha para std::swap .

Há pouco a acrescentar à resposta de Peter Alexander. Deixe-me mencionar apenas um uso no qual a especialização de function poderia ser preferível sobre sobrecarga: se você tiver que selecionar entre funções sem parâmetros .

Por exemplo

 template T zero(); template<> int zero() { return 0; } template<> long zero() { return 0L; } 

Para fazer algo semelhante usando a sobrecarga de function, você teria que adicionar um parâmetro à assinatura da function:

 int zero(int) { return 0; } long zero(long) { return 0L; } 

Você não tem permissão para sobrecarregar funções no namespace std , mas tem permissão para especializar modelos (se bem me lembro), então essa é uma opção.

A outra opção é colocar sua function de swap no mesmo namespace que a coisa que está operando e using std::swap; antes de chamar um swap não qualificado.