Saya menggunakan fungsi SFINAE dalam suatu proyek dan saya tidak yakin apakah ada perbedaan antara dua pendekatan berikut (selain gaya):
#include <cstdlib>
#include <type_traits>
#include <iostream>
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo()
{
std::cout << "method 1" << std::endl;
}
template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0>
void foo()
{
std::cout << "method 2" << std::endl;
}
int main()
{
foo<int>();
foo<double>();
std::cout << "Done...";
std::getchar();
return EXIT_SUCCESS;
}
Output program seperti yang diharapkan:
method 1
method 2
Done...
Saya telah melihat metode 2 lebih sering digunakan dalam stackoverflow, tetapi saya lebih suka metode 1.
Apakah ada keadaan ketika kedua pendekatan ini berbeda?
Jawaban:
Saran: lebih suka metode 2.
Kedua metode bekerja dengan fungsi tunggal. Masalah muncul ketika Anda memiliki lebih dari satu fungsi, dengan tanda tangan yang sama, dan Anda ingin mengaktifkan hanya satu fungsi dari set.
Misalkan Anda ingin mengaktifkan
foo()
, versi 1, ketikabar<T>()
(berpura-pura itu adalahconstexpr
fungsi) adalahtrue
, danfoo()
, versi 2, ketikabar<T>()
adalahfalse
.Dengan
Anda mendapatkan kesalahan kompilasi karena Anda memiliki ambiguitas: dua
foo()
fungsi dengan tanda tangan yang sama (parameter templat default tidak mengubah tanda tangan).Namun solusi berikut
berfungsi, karena SFINAE memodifikasi tanda tangan fungsi.
Pengamatan yang tidak terkait: ada juga metode ketiga: aktifkan / nonaktifkan tipe kembali (kecuali untuk konstruktor kelas / struktur, jelas)
Sebagai metode 2, metode 3 kompatibel dengan pemilihan fungsi alternatif dengan tanda tangan yang sama.
sumber
foo()
fungsi tetap tersedia saat Anda memanggilnya dengan parameter templat kedua eksplisit (foo<double, double>();
panggilan). Dan jika tetap tersedia, ada ambiguitas dengan versi lainnya. Dengan metode 2, SFINAE mengaktifkan / menonaktifkan argumen kedua, bukan parameter default. Jadi Anda tidak dapat menyebutnya explicating the parameter karena ada kegagalan substitusi yang tidak mengizinkan parameter kedua. Jadi versi ini tidak tersedia, jadi tidak ada ambiguitasauto foo() -> std::enable_if_t<...>
ini sering berguna untuk menghindari menyembunyikan tanda tangan fungsi dan untuk memungkinkan menggunakan argumen fungsi.Selain jawaban max66 , alasan lain untuk memilih metode 2 adalah bahwa dengan metode 1, Anda dapat (secara tidak sengaja) melewati parameter tipe eksplisit sebagai argumen templat kedua dan mengalahkan mekanisme SFINAE sepenuhnya. Ini bisa terjadi sebagai kesalahan ketik, kesalahan salin / tempel, atau sebagai kekeliruan dalam mekanisme templat yang lebih besar.
Demo langsung di sini
sumber