Saya baru saja melihat Stephan T. Lavavej berbicara di CppCon 2018
"Pengurangan Argumen Template Kelas", di mana pada titik tertentu dia secara tidak sengaja mengatakan:
Dalam tipe C ++ informasi hampir tidak pernah mengalir ke belakang ... Saya harus mengatakan "hampir" karena ada satu atau dua kasus, mungkin lebih tetapi sangat sedikit .
Meskipun mencoba mencari tahu kasus mana yang mungkin dia maksud, saya tidak dapat menemukan apa pun. Karena itu pertanyaannya:
Dalam kasus apa standar C ++ 17 mengamanatkan bahwa informasi jenis menyebar mundur?
c++
types
language-lawyer
c++17
type-deduction
Massimiliano
sumber
sumber
Jawaban:
Ini setidaknya satu kasus:
struct foo { template<class T> operator T() const { std::cout << sizeof(T) << "\n"; return {}; } };
jika Anda melakukannya
foo f; int x = f; double y = f;
, informasi jenis akan mengalir "mundur" untuk mencari tahu apa yangT
ada di dalamnyaoperator T
.Anda dapat menggunakan ini dengan cara yang lebih maju:
template<class T> struct tag_t {using type=T;}; template<class F> struct deduce_return_t { F f; template<class T> operator T()&&{ return std::forward<F>(f)(tag_t<T>{}); } }; template<class F> deduce_return_t(F&&)->deduce_return_t<F>; template<class...Args> auto construct_from( Args&&... args ) { return deduce_return_t{ [&](auto ret){ using R=typename decltype(ret)::type; return R{ std::forward<Args>(args)... }; }}; }
jadi sekarang saya bisa melakukannya
std::vector<int> v = construct_from( 1, 2, 3 );
dan berhasil.
Tentu saja, mengapa tidak dilakukan saja
{1,2,3}
? Yah,{1,2,3}
itu bukan ekspresi.std::vector<std::vector<int>> v; v.emplace_back( construct_from(1,2,3) );
yang memang membutuhkan lebih banyak sihir: Contoh langsung . (Saya harus membuat deduce return melakukan pemeriksaan SFINAE dari F, lalu membuat F menjadi SFINAE ramah, dan saya harus memblokir std :: initializer_list di deduce_return_t operator T.)
sumber
&&
kualifikasi dioperator T()
adalah sentuhan yang hebat; ini membantu menghindari interaksi yang buruk denganauto
menyebabkan kesalahan kompilasi jikaauto
disalahgunakan di sini.Stephan T. Lavavej menjelaskan kasus yang dia bicarakan dalam sebuah tweet :
kita dapat melihat contohnya dari halaman cppreference di Address of overloaded function , saya telah mengecualikan beberapa di bawah ini:
int f(int) { return 1; } int f(double) { return 2; } void g( int(&f1)(int), int(*f2)(double) ) {} int main(){ g(f, f); // selects int f(int) for the 1st argument // and int f(double) for the second auto foo = []() -> int (*)(int) { return f; // selects int f(int) }; auto p = static_cast<int(*)(int)>(f); // selects int f(int) }
Michael Park menambahkan :
dan memberikan contoh langsung ini :
void overload(int, int) {} void overload(int, int, int) {} template <typename T1, typename T2, typename A1, typename A2> void f(void (*)(T1, T2), A1&&, A2&&) {} template <typename T1, typename T2, typename T3, typename A1, typename A2, typename A3> void f(void (*)(T1, T2, T3), A1&&, A2&&, A3&&) {} int main () { f(&overload, 1, 2); }
yang saya uraikan lebih lanjut di sini .
sumber
Saya percaya pada pengecoran statis fungsi kelebihan beban, aliran berjalan ke arah yang berlawanan seperti pada resolusi kelebihan beban biasa. Jadi salah satunya mundur, saya kira.
sumber