Удаленная функция неявно встроена
(Приложение к существующим ответам)
... И удаленная функция должна быть первым объявлением функции (кромедля удаления явных специализаций шаблонов функций - удаление должно быть при первом объявлении специализации), то есть вы не можете объявить функцию, а затем удалить ее, скажем, при определении локально для единицы перевода.
Цитирование [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; */
}