Pertanyaan Dapatkah jenis kontainer disimpulkan dalam template variad?


Dalam C ++ 11 / C ++ 14,

template <
   typename T ,
   template <typename...> class Container_t
>
void MyFunc(Container_t<T> &data) { ... }


template <typename T>
void MyFunc2( T v ) { ... }


int main()
{
   std::vector<char> v;

   MyFunc<char, std::vector>(v);     // OK
   MyFunc(v);                        // error

   int i;

   MyFunc2<int>(i);                  // OK
   MyFunc2(i);                       // OK
}

Saya mendapatkan kesalahan dengan MyFunc(v).

Apakah mungkin dengan cara apa pun untuk membiarkan compiler mengetahui jenis wadah yang diteruskan ke fungsi template variadic? Saya tidak menemukan masalah dalam menemukannya, seperti tipe normal dalam template normal.

Jika saya perlu mengubah jenis v, apakah saya harus memperbaiki semua panggilan ke MyFunc?

Compiler: Microsoft Visual C ++ 2015 (v140)


4
2018-05-19 17:06


asal


Jawaban:


Triknya adalah menamai argumen template template:

#include <vector>
#include <iostream>
#include <typeinfo>

template <
   typename T ,
   typename A,
   template <typename = T, typename = A> class Container_t
>
void MyFunc(Container_t<T, A> &data) { 
     std::cout << "value type = " << typeid(T).name() << std::endl;
     std::cout << "allocator type = " << typeid(A).name() << std::endl;
     std::cout << "container type = " << typeid(Container_t<T,A>).name() << std::endl;
   }


template <typename T>
void MyFunc2( T v ) {  }


int main()
{
   std::vector<char> v;

   MyFunc<char, std::allocator<char>, std::vector>(v);     // OK
   MyFunc(v);                        // now ok

}

Jika Anda tidak peduli tentang apa pun kecuali jenis nilai dan wadahnya ...

#include <vector>
#include <map>
#include <iostream>
#include <typeinfo>

template <
   typename T ,
   typename...Rest,
   template <typename, typename...> class Container_t
>
void MyFunc(Container_t<T, Rest...> &data) { 
     std::cout << "value type = " << typeid(T).name() << std::endl;
     std::cout << "container type = " << typeid(Container_t<T,Rest...>).name() << std::endl;
   }


template <typename T>
void MyFunc2( T v ) {  }


int main()
{
   std::vector<char> v;
   std::map<char, int> m;

//   MyFunc<char, std::allocator<char>, std::vector>(v);     // OK
   MyFunc(v);                        // now ok
   MyFunc(m);                        // now ok

}

4
2018-05-19 17:27



Alih-alih mencoba menyimpulkan jenis kontainer, menganggap kontainer mendefinisikan jenis apa yang disimpannya.

template <typename Container>
void MyFunc(Container& data)
{ 
   // all std containers defines value_type member (also reference etc.)
   using std::begin;
   using value_type = typename Container::value_type;
   value_type value = *begin(data);
  ...
}

Harap dicatat, bahwa Anda mungkin tidak memerlukan jenis elemen yang disimpan sama sekali:

template <typename Container>
void MyFunc(Container& data)
{ 
   using std::begin;
   auto value = *begin(data);
  ...
}

jika Anda ingin bekerja pada kontainer std saja (atau yang dengan argumen template serupa) - lihat Richard Hodges menjawab.


8
2018-05-19 17:17



Dugaan saya adalah bahwa ini adalah bug VC ++ karena GCC dan CLANG dapat menyimpulkan parameter template input. Seperti yang diusulkan oleh KerrekSB di komentar yang kurang menyakitkan kerja-sekitar akan menjadi berikut:

template<typename T, template<typename...> class Container_t, typename... Args>
void MyFunc(Container_t<T, Args...> &data) { 
  ...
}

Demo Live


1
2018-05-19 17:55