Melihat kemungkinan implementasi konsep same_as di https://en.cppreference.com/w/cpp/concepts/same_as saya perhatikan ada sesuatu yang aneh sedang terjadi.
namespace detail {
template< class T, class U >
concept SameHelper = std::is_same_v<T, U>;
}
template< class T, class U >
concept same_as = detail::SameHelper<T, U> && detail::SameHelper<U, T>;
Pertanyaan pertama adalah mengapa sebuah SameHelper
konsep digabungkan? Yang kedua adalah mengapa same_as
memeriksa apakah T
sama U
dan U
sama dengan T
? Bukankah itu berlebihan?
SameHelper<T, U>
mungkin benar bukan berartiSameHelper<U, T>
mungkin.is_same<T, U>::value == true
jika dan hanya jikais_same<U, T>::value == true
." Ini menyiratkan bahwa pemeriksaan ganda ini tidak perluJawaban:
Pertanyaan menarik. Saya baru-baru ini menyaksikan pembicaraan Andrew Sutton tentang Konsep, dan dalam sesi tanya jawab seseorang menanyakan pertanyaan berikut (cap waktu di tautan berikut): CppCon 2018: Andrew Sutton “Konsep dalam 60: Segala sesuatu yang perlu Anda ketahui dan tidak ada yang tidak Anda lakukan”
Jadi pertanyaannya bermuara pada:
If I have a concept that says A && B && C, another says C && B && A, would those be equivalent?
Andrew menjawab ya, tetapi menunjukkan fakta bahwa kompiler memiliki beberapa metode internal (yang transparan bagi pengguna) untuk menguraikan konsep menjadi proposisi logis atom (atomic constraints
seperti kata Andrew istilah) dan memeriksa apakah mereka setara.Sekarang lihat apa yang dikatakan cppreference
std::same_as
:Ini pada dasarnya adalah hubungan "jika-dan-hanya-jika": mereka menyiratkan satu sama lain. (Kesetaraan Logis)
Dugaan saya adalah bahwa di sini kendala atomnya
std::is_same_v<T, U>
. Cara memperlakukan kompilerstd::is_same_v
mungkin membuat mereka berpikirstd::is_same_v<T, U>
danstd::is_same_v<U, T>
sebagai dua kendala yang berbeda (mereka adalah entitas yang berbeda!). Jadi jika Anda menerapkanstd::same_as
hanya menggunakan salah satu dari mereka:Kemudian
std::same_as<T, U>
danstd::same_as<U, T>
akan "meledak" ke berbagai batasan atom dan menjadi tidak setara.Nah, mengapa kompiler peduli?
Pertimbangkan contoh ini :
Idealnya,
my_same_as<T, U> && std::integral<T>
subsidimy_same_as<U, T>
; oleh karena itu, kompiler harus memilih spesialisasi templat kedua, kecuali ... tidak: kompiler memancarkan kesalahanerror: call of overloaded 'foo(int, int)' is ambiguous
.Alasan di balik ini adalah bahwa karena
my_same_as<U, T>
danmy_same_as<T, U>
tidak saling menyatukan,my_same_as<T, U> && std::integral<T>
danmy_same_as<U, T>
menjadi tak tertandingi (pada set kendala yang dipesan sebagian di bawah hubungan subsumsi).Namun, jika Anda mengganti
dengan
Kode mengkompilasi.
sumber
SameHelper
: itu membuat dua kegunaan dariis_same_v
berasal dari ekspresi yang sama.is_same<T, U>
yang identik denganis_same<U, T>
, dua batasan atom tidak dianggap identik kecuali mereka juga dibentuk dari ekspresi yang sama. Maka dari itu kebutuhan untuk keduanya.are_same_as
?template<typename T, typename U0, typename... Un> concept are_same_as = SameAs<T, U0> && (SameAs<T, Un> && ...);
akan gagal dalam beberapa kasus. Sebagai contohare_same_as<T, U, int>
akan setara denganare_same_as<T, int, U>
tetapi tidak untukare_same_as<U, T, int>
std::is_same
didefinisikan sebagai true jika dan hanya jika:Sejauh yang saya tahu, standar tidak mendefinisikan arti "tipe yang sama", tetapi dalam bahasa alami dan logika "sama" adalah hubungan ekivalensi dan dengan demikian bersifat komutatif.
Mengingat asumsi ini, yang saya anggap,
is_same_v<T, U> && is_same_v<U, V>
memang akan berlebihan. Tetapisame_as
tidak ditentukan dalam halis_same_v
; itu hanya untuk eksposisi.Pemeriksaan eksplisit untuk keduanya memungkinkan implementasi untuk
same-as-impl
memuaskansame_as
tanpa komutatif. Menentukannya dengan cara ini menjelaskan dengan tepat bagaimana konsep itu berperilaku tanpa membatasi bagaimana itu bisa diimplementasikan.Tepatnya mengapa pendekatan ini dipilih alih-alih menentukan dalam hal
is_same_v
, saya tidak tahu. Keuntungan dari pendekatan yang dipilih adalah bahwa kedua definisi tersebut tidak dapat digabungkan. Satu tidak tergantung pada yang lain.sumber