Diberikan:
#include <concepts>
#include <iostream>
template<class T>
struct wrapper;
template<std::signed_integral T>
struct wrapper<T>
{
wrapper() = default;
void print()
{
std::cout << "signed_integral" << std::endl;
}
};
template<std::integral T>
struct wrapper<T>
{
wrapper() = default;
void print()
{
std::cout << "integral" << std::endl;
}
};
int main()
{
wrapper<int> w;
w.print(); // Output : signed_integral
return 0;
}
Dari kode di atas, int
memenuhi syarat untuk keduanya std::integral
dan std::signed_integral
konsep.
Anehnya ini mengkompilasi dan mencetak "signed_integral" pada kedua kompiler GCC dan MSVC. Saya mengharapkannya gagal dengan kesalahan di sepanjang baris "spesialisasi template sudah didefinisikan".
Oke, itu legal, cukup adil, tetapi mengapa std::signed_integral
dipilih alih-alih std::integral
? Apakah ada aturan yang didefinisikan dalam standar dengan spesialisasi template apa yang dipilih ketika beberapa konsep memenuhi syarat untuk argumen template?
c++
language-lawyer
c++20
c++-concepts
Lewis Liman
sumber
sumber
Jawaban:
Ini karena konsep dapat lebih terspesialisasi daripada yang lain, sedikit seperti cara templat memesan sendiri. Ini disebut pemesanan sebagian kendala
Dalam hal konsep, mereka saling menggantikan ketika mereka memasukkan kendala yang setara. Misalnya, inilah caranya
std::integral
danstd::signed_integral
diterapkan:Menormalkan kendala-kendala yang dikompilasi oleh kompiler hingga ekspresi contraint ini:
Dalam contoh ini,
signed_integral
tersiratintegral
sepenuhnya. Jadi, dalam arti tertentu, integral yang ditandatangani "lebih terbatas" daripada integral.Standar menulisnya seperti ini:
Dari [temp.func.order] / 2 (penekanan saya):
Itu berarti bahwa jika ada beberapa kemungkinan penggantian untuk templat dan keduanya dipilih dari pemesanan parsial, itu akan memilih templat yang paling terbatas.
Dari [temp.constr.order] / 1 :
Ini menjelaskan algoritma subsumsi yang digunakan kompiler untuk memesan batasan, dan karenanya konsep.
sumber
C ++ 20 memiliki mekanisme untuk memutuskan ketika satu entitas terbatas tertentu "lebih terbatas" daripada yang lain. Ini bukan hal yang sederhana.
Ini dimulai dengan konsep memecah kendala menjadi komponen atomnya, sebuah proses yang disebut normalisasi kendala . Ini besar dan terlalu rumit untuk dimasukkan ke sini, tetapi ide dasarnya adalah bahwa setiap ekspresi dalam batasan dipecah menjadi potongan-potongan konseptual atom, secara rekursif, sampai Anda mencapai sub-ekspresi komponen yang bukan konsep.
Karena itu, mari kita lihat bagaimana
integral
dansigned_integral
konsep didefinisikan :Dekomposisi
integral
adalah adilis_integral_v
. Dekomposisisigned_integral
adalahis_integral_v && is_signed_v
.Sekarang, kita sampai pada konsep subsumption kendala . Agak rumit, tetapi ide dasarnya adalah bahwa kendala C1 dikatakan "subsume" kendala C2 jika dekomposisi C1 berisi setiap sub-ekspresi dalam C2. Kita dapat melihat bahwa
integral
itu tidak merangkumsigned_integral
, tetapisigned_integral
juga menggabungintegral
, karena itu berisi semuanyaintegral
.Selanjutnya, kita sampai pada pemesanan entitas terbatas:
Karena
signed_integral
bersubsidiintegral
,<signed_integral> wrapper
itu "setidaknya dibatasi" sebagai<integral> wrapper
. Namun, kebalikannya tidak benar, karena subsuminya tidak dapat dibalikkan.Oleh karena itu, sesuai dengan aturan untuk entitas yang "lebih terbatas":
Karena
<integral> wrapper
setidaknya tidak dibatasi<signed_integral> wrapper
, maka yang terakhir dianggap lebih dibatasi daripada yang sebelumnya.Dan karena itu, ketika keduanya bisa berlaku, deklarasi yang lebih terbatas menang.
Ketahuilah bahwa aturan pembatas subsubs berhenti ketika ekspresi ditemukan yang bukan a
concept
. Jadi, jika Anda melakukan ini:Dalam hal ini,
my_signed_integral
tidak akan berlanggananstd::integral
. Meskipunmy_is_integral_v
didefinisikan secara identikstd::is_integral_v
, karena itu bukan konsep, aturan subsumsi C ++ tidak dapat mengintip melalui itu untuk menentukan bahwa mereka sama.Jadi aturan subsumsi mendorong Anda untuk membangun konsep dari operasi pada konsep atom.
sumber
Dengan Partial_ordering_of_constraints
dan
Dan konsep
std::signed_integral
menggolongkanstd::integral<T>
konsep:Jadi kode Anda ok, karena
std::signed_integral
lebih "khusus".sumber