Bayangkan Anda seorang pelajar yang mempelajari fitur C++ modern. Dan Anda diberi masalah pada topik konsep / kendala . Guru, tentu saja, memiliki solusi referensi "bagaimana melakukannya dengan benar", tetapi tidak jelas bagi Anda, dan Anda akan menemukan segunung kode yang agak membingungkan yang masih tidak berfungsi. (Dan Anda menambahkan dan menulis lebih banyak dan lebih banyak kelebihan dan spesialisasi templat, yang mencakup semakin banyak klaim baru dari kompiler).
Sekarang bayangkan Anda adalah seorang guru yang melihat gunung ini dan ingin membantu muridnya. Anda mulai menyederhanakan dan menyederhanakan kodenya, dan bahkan dengan bodoh mengomentari potongan unit test untuk membuatnya bekerja entah bagaimana ... Tapi tetap tidak berhasil. Selain itu, tergantung pada urutan tes unit, itu menghasilkan hasil yang berbeda atau tidak dikumpulkan sama sekali. Di suatu tempat tersembunyi perilaku tidak terdefinisi. Tapi yang mana?
Pertama, guru (yaitu, saya) memperkecil kode menjadi seperti ini: https://gcc.godbolt.org/z/TaMTWqc1T
//
template<class T> concept Ptr = requires(T t) { *t; };
template<class T> concept Vec = requires(T t) { t.begin(); t[0]; };
// ,
template<class T> void f(T t) { // (1)
std::cout << "general case " << __PRETTY_FUNCTION__ << std::endl;
}
template<Ptr T> void f(T t) { // (2)
std::cout << "pointer to ";
f(*t); // ,
}
template<Vec T> void f(T t) { // (3)
std::cout << "vector of ";
f(t[0]); // ,
}
// ( )
int main() {
std::vector<int> v = {1};
//
f(v);
//
f(&v);
//
f(&v);
f(v);
//
f(v);
f(&v);
}
Kami mengharapkan itu
f (v) akan mencetak "vektor dari kasus umum void f (T) [T = int]"
f (& v) akan mencetak "penunjuk ke vektor kasus umum void f (T) [T = int]"
Sebagai gantinya, kita mendapatkan
: "vektor kasus umum batal f (T) [T = int]"
B: "pointer dari kasus umum void f (T) [T = std :: vector <int>]" -?
: clang
"pointer to general case void foo(T) [T = std::vector<int>]" —
"general case void foo(T) [T = std::vector<int>]", — , !
gcc —
: clang gcc
?!
. — , (2) (1) (2), (1).
: https://gcc.godbolt.org/z/47qhYv6q4
void f(int x) { std::cout << "int" << std::endl; }
void g(char* p) { std::cout << "char* -> "; f(*p); } // f(int)
void f(char x) { std::cout << "char" << std::endl; }
void g(char** p) { std::cout << "char** -> "; f(**p); } // f(char)
int main() {
char x;
char* p = &x;
f(x); // char
g(p); // char* -> int
g(&p); // char** -> char
}
- - , , — , .
- , , - , () .
, . . , ODR?
:
template<class T> void f(T t) {.....}
template<class T> void f(T t) requires Ptr<T> {.....}
template<class T> void f(T t) requires Vec<T> {.....}
. . , .
SFINAE, https://gcc.godbolt.org/z/4sar6W6Kq
// char int -
template<class T, class = void> void f(T t, char) {.....}
template<class T> auto f(T t, int) -> std::enable_if_t<Ptr<T>, void> {.....}
template<class T> auto f(T t, int) -> std::enable_if_t<Vec<T>, void> {.....}
..... f(v, 0) .....
..... f(&v, 0) .....
, https://gcc.godbolt.org/z/PsdhsG6Wr
template<class T> void f(T t) {.....}
template<class T> void f(T* t) {.....}
template<class T> void f(std::vector<T> t) {.....}
. , ( - - ), ( f(T*) "general case", main - "vector").
/?
, RSDN, !
4 :
template<class T> void f() {}
void g() { f<int>(); }
template<class T> void f() requires true {}
void h() { f<int>(); }
, . g() , h() - .
! .
, (clang ≤ 12.0, gcc ≤ 12.0) requires . - MSVC6 , ...
, , , . : " -, ill-formed, " (, ill-formed " ", " "...)
2017 , .
. - . , , - . ( , — , ).