Uma função excluída está implicitamente embutida
(Adenda às respostas existentes)
... E uma função excluída deve ser a primeira declaração da função (exceto para excluir especializações explícitas de modelos de função - a exclusão deve estar na primeira declaração da especialização), o que significa que você não pode declarar uma função e depois excluí-la, por exemplo, na sua definição local para uma unidade de tradução.
Citando [dcl.fct.def.delete] / 4 :
Uma função excluída está implicitamente embutida. ( Nota: a regra de definição única ( [basic.def.odr] ) se aplica a definições excluídas. - end note ] Uma definição excluída de uma função deve ser a primeira declaração da função ou, para uma especialização explícita de um modelo de função. , a primeira declaração dessa especialização. [Exemplo:
struct sometype {
sometype();
};
sometype::sometype() = delete; // ill-formed; not first declaration
- exemplo final )
Um modelo de função principal com uma definição excluída pode ser especializado
Embora uma regra geral geral seja evitar a especialização de modelos de função, uma vez que as especializações não participam da primeira etapa da resolução de sobrecarga, existem alguns contextos discutíveis em que isso pode ser útil. Por exemplo, ao usar um modelo de função principal não sobrecarregado sem definição para corresponder a todos os tipos que não seria implicitamente convertido em uma sobrecarga correspondente por conversão; ou seja, remover implicitamente várias correspondências implícitas de conversão implementando apenas correspondências exatas de tipo na especialização explícita do modelo de função principal não definido e não sobrecarregado.
Antes do conceito de função excluída do C ++ 11, era possível simplesmente omitir a definição do modelo de função principal, mas isso gerava erros de referência indefinidos obscuros que, sem dúvida, não deram nenhuma intenção semântica ao autor do modelo de função primária (omitido intencionalmente) ?). Se, em vez disso, excluirmos explicitamente o modelo de função principal, as mensagens de erro, caso não seja encontrada nenhuma especialização explícita adequada, ficarão muito mais agradáveis e também mostrarão que a omissão / exclusão da definição do modelo de função principal foi intencional.
#include <iostream>
#include <string>
template< typename T >
void use_only_explicit_specializations(T t);
template<>
void use_only_explicit_specializations<int>(int t) {
std::cout << "int: " << t;
}
int main()
{
const int num = 42;
const std::string str = "foo";
use_only_explicit_specializations(num); // int: 42
//use_only_explicit_specializations(str); // undefined reference to `void use_only_explicit_specializations< ...
}
No entanto, em vez de simplesmente omitir uma definição para o modelo de função principal acima, produzindo um erro de referência indefinido obscuro quando nenhuma especialização explícita corresponder, a definição do modelo primário pode ser excluída:
#include <iostream>
#include <string>
template< typename T >
void use_only_explicit_specializations(T t) = delete;
template<>
void use_only_explicit_specializations<int>(int t) {
std::cout << "int: " << t;
}
int main()
{
const int num = 42;
const std::string str = "foo";
use_only_explicit_specializations(num); // int: 42
use_only_explicit_specializations(str);
/* error: call to deleted function 'use_only_explicit_specializations'
note: candidate function [with T = std::__1::basic_string<char>] has
been explicitly deleted
void use_only_explicit_specializations(T t) = delete; */
}
Apresentando uma mensagem de erro mais legível, em que a intenção de exclusão também é claramente visível (onde um erro de referência indefinido pode levar o desenvolvedor a pensar que isso é um erro imprudente).
Voltando ao motivo de querermos usar essa técnica? Mais uma vez, especializações explícitas poderiam ser úteis para implicitamente remover conversões implícitas.
#include <cstdint>
#include <iostream>
void warning_at_best(int8_t num) {
std::cout << "I better use -Werror and -pedantic... " << +num << "\n";
}
template< typename T >
void only_for_signed(T t) = delete;
template<>
void only_for_signed<int8_t>(int8_t t) {
std::cout << "UB safe! 1 byte, " << +t << "\n";
}
template<>
void only_for_signed<int16_t>(int16_t t) {
std::cout << "UB safe! 2 bytes, " << +t << "\n";
}
int main()
{
const int8_t a = 42;
const uint8_t b = 255U;
const int16_t c = 255;
const float d = 200.F;
warning_at_best(a); // 42
warning_at_best(b); // implementation-defined behaviour, no diagnostic required
warning_at_best(c); // narrowing, -Wconstant-conversion warning
warning_at_best(d); // undefined behaviour!
only_for_signed(a);
only_for_signed(c);
//only_for_signed(b);
/* error: call to deleted function 'only_for_signed'
note: candidate function [with T = unsigned char]
has been explicitly deleted
void only_for_signed(T t) = delete; */
//only_for_signed(d);
/* error: call to deleted function 'only_for_signed'
note: candidate function [with T = float]
has been explicitly deleted
void only_for_signed(T t) = delete; */
}