Fungsi yang dihapus secara implisit sebaris
(Tambahan untuk jawaban yang ada)
... Dan fungsi yang dihapus akan menjadi deklarasi pertama dari fungsi (kecuali untuk menghapus spesialisasi eksplisit dari templat fungsi - penghapusan harus pada deklarasi pertama spesialisasi), yang berarti Anda tidak dapat mendeklarasikan fungsi dan kemudian menghapusnya, katakanlah, pada definisi lokal ke unit terjemahan.
Mengutip [dcl.fct.def.delete] / 4 :
Fungsi yang dihapus secara implisit sebaris. ( Catatan: Aturan satu-definisi ( [basic.def.odr] ) berlaku untuk definisi yang dihapus. - Catatan akhir ] Definisi yang dihapus dari suatu fungsi harus merupakan deklarasi fungsi pertama atau, untuk spesialisasi eksplisit dari templat fungsi. , deklarasi pertama spesialisasi itu. [Contoh:
struct sometype {
sometype();
};
sometype::sometype() = delete; // ill-formed; not first declaration
- contoh akhir )
Templat fungsi utama dengan definisi yang dihapus dapat dikhususkan
Meskipun aturan umum adalah untuk menghindari templat fungsi khusus karena spesialisasi tidak berpartisipasi dalam langkah pertama resolusi kelebihan beban, ada beberapa konteks yang dapat diperdebatkan. Misalnya ketika menggunakan templat fungsi utama yang tidak kelebihan beban tanpa definisi untuk mencocokkan semua jenis yang tidak ingin orang dikonversi secara implisit ke kelebihan beban yang sesuai dengan konversi; yaitu, untuk secara implisit menghapus sejumlah kecocokan konversi-konversi dengan hanya menerapkan kecocokan jenis yang tepat dalam spesialisasi eksplisit dari templat fungsi primer yang tidak didefinisikan, tidak kelebihan beban.
Sebelum konsep fungsi C ++ 11 yang dihapus, orang bisa melakukan ini hanya dengan menghilangkan definisi templat fungsi utama, tetapi ini memberikan kesalahan referensi yang tidak terdefinisi yang tidak jelas yang tidak memberikan maksud semantik sama sekali dari pembuat templat fungsi primer (sengaja dihilangkan) ?). Jika kita sebaliknya secara eksplisit menghapus templat fungsi utama, pesan kesalahan jika tidak ditemukan spesialisasi eksplisit yang cocok menjadi jauh lebih baik, dan juga menunjukkan bahwa penghilangan / penghapusan definisi templat fungsi primer disengaja.
#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< ...
}
Namun, alih-alih hanya menghilangkan definisi untuk templat fungsi utama di atas, menghasilkan kesalahan referensi yang tidak terdefinisi yang tidak jelas ketika tidak ada spesialisasi eksplisit yang cocok, definisi templat primer dapat dihapus:
#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; */
}
Menghasilkan pesan kesalahan yang lebih mudah dibaca, di mana niat penghapusan juga terlihat jelas (di mana kesalahan referensi yang tidak terdefinisi dapat menyebabkan pengembang menganggap ini kesalahan yang tidak terpikirkan).
Kembali ke mengapa kita ingin menggunakan teknik ini? Sekali lagi, spesialisasi eksplisit dapat berguna untuk secara implisit menghapus konversi implisit.
#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; */
}