Видалена функція неявно вбудована
(Додаток до існуючих відповідей)
... І видалена функція має бути першим оголошенням функції (за винятком видалення явних спеціалізацій шаблонів функцій - видалення має бути при першому оголошенні спеціалізації), тобто ви не можете оголосити функцію та пізніше видалити її, скажімо, за його визначенням, локальним для перекладацької одиниці.
Посилаючись на [dcl.fct.def.delete] / 4 :
Видалена функція неявно вбудована. ( Примітка . Правило одного визначення ( [basic.def.odr] ) застосовується до видалених визначень. - кінцева примітка ] Видалене визначення функції є першим оголошенням функції або для явної спеціалізації шаблону функції , перша декларація цієї спеціалізації. [Приклад:
struct sometype {
sometype();
};
sometype::sometype() = delete; // ill-formed; not first declaration
- кінцевий приклад )
Шаблон основної функції із видаленим визначенням може бути спеціалізованим
Хоча загальним правилом є уникнення спеціалізованих шаблонів функцій, оскільки спеціалізації не беруть участі у першому кроці вирішення перевантаження, є суперечливі контексти, де це може бути корисно. Наприклад, при використанні неперевантаженого шаблону первинної функції без визначення, щоб відповідати всім типам, які не хотіли б, щоб неявно перетворитись на інакше перевантаження зі збігом переходів; тобто неявно видалити ряд збігів неявної конверсії, лише реалізуючи відповідність точного типу в явній спеціалізації не визначеного шаблону неперевантаженої основної функції.
Перед вилученою концепцією функції C ++ 11 можна було це зробити, просто опустивши визначення шаблону первинної функції, але це дало незрозумілі невизначені посилання помилки, які, можливо, не давали жодного смислового наміру від автора шаблону первинної функції (навмисно опущено ?). Якщо ми замість цього явно видалимо шаблон основного функціоналу, повідомлення про помилки, якщо не знайдена відповідна явна спеціалізація, стає набагато приємнішою, а також показує, що упущення / видалення визначення шаблону основної функції було навмисним.
#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< ...
}
Однак, замість того, щоб просто опустити визначення шаблону основної функції вище, видаючи незрозумілу невизначену посилання, коли явна спеціалізація не збігається, визначення основного шаблону можна видалити:
#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; */
}
Подаючи більш читабельне повідомлення про помилку, де наміри видалення також добре видно (де невизначена помилка посилання може призвести до того, що розробник вважає це непродуманою помилкою).
Повертаючись до того, чому ми хотіли б коли-небудь використовувати цю техніку? Знову ж таки, явні спеціалізації можуть бути корисними для неявного усунення неявних перетворень.
#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; */
}