Une fonction supprimée est implicitement en ligne
(Addendum aux réponses existantes)
... Et une fonction supprimée doit être la première déclaration de la fonction (sauf pour la suppression de spécialisations explicites de modèles de fonction - la suppression doit se faire à la première déclaration de la spécialisation), ce qui signifie que vous ne pouvez pas déclarer une fonction et la supprimer plus tard, par exemple, à sa définition locale à une unité de traduction.
Citant [dcl.fct.def.delete] / 4 :
Une fonction supprimée est implicitement en ligne. ( Remarque: la règle à une définition ( [basic.def.odr] ) s'applique aux définitions supprimées. - note de fin ] Une définition supprimée d'une fonction doit être la première déclaration de la fonction ou, pour une spécialisation explicite d'un modèle de fonction , la première déclaration de cette spécialisation. [Exemple:
struct sometype {
sometype();
};
sometype::sometype() = delete; // ill-formed; not first declaration
- fin exemple )
Un modèle de fonction principale avec une définition supprimée peut être spécialisé
Bien qu'une règle générale soit d'éviter la spécialisation des modèles de fonction car les spécialisations ne participent pas à la première étape de la résolution des surcharges, il existe certains contextes où cela peut être utile. Par exemple, lors de l'utilisation d'un modèle de fonction principale non surchargé sans définition pour correspondre à tous les types que l'on ne voudrait pas implicitement convertis en une surcharge par correspondance par conversion; c'est-à-dire pour supprimer implicitement un certain nombre de correspondances de conversion implicite en implémentant uniquement des correspondances de type exact dans la spécialisation explicite du modèle de fonction principale non défini et non surchargé.
Avant le concept de fonction supprimé de C ++ 11, on pouvait le faire en omettant simplement la définition du modèle de fonction principale, mais cela donnait des erreurs de référence indéfinies obscures qui sans doute ne donnaient aucune intention sémantique de l'auteur du modèle de fonction primaire (intentionnellement omis ?). Si au lieu de cela, nous supprimons explicitement le modèle de fonction principale, les messages d'erreur au cas où aucune spécialisation explicite appropriée ne serait trouvée deviennent beaucoup plus agréables et montrent également que l'omission / la suppression de la définition du modèle de fonction principale était intentionnelle.
#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< ...
}
Cependant, au lieu d'omettre simplement une définition du modèle de fonction principal ci-dessus, ce qui génère une erreur de référence obscure non définie lorsqu'aucune spécialisation explicite ne correspond, la définition du modèle principal peut être supprimée:
#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; */
}
Donner un message d'erreur plus lisible, où l'intention de suppression est également clairement visible (où une erreur de référence non définie pourrait conduire le développeur à penser que c'est une erreur irréfléchie).
Revenons à pourquoi voudrions-nous jamais utiliser cette technique? Encore une fois, des spécialisations explicites pourraient être utiles pour implicitement supprimer les conversions implicites.
#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; */
}