Selezione di un'implementazione delle funzioni basata su iteratore :: Value_type
Domanda
Sto cercando un modo ragionevole per selezionare un ordinamento algoritmo in base al tipo di valore del contenitore.
Nella sua forma corrente posso dedurre il corretto sort(a, b)
per dati interi / non intesi.
#include <cstdlib>
#include <type_traits>
#include <algorithm>
#include <vector>
#include <iostream>
namespace sort_selector{
template<typename T>
void _radix_sort(T begin, T end){
// radix implementation
}
template<typename T>
typename std::enable_if<
std::is_integral<typename T::value_type>::value>::type
sort(T begin, T end){
std::cout << "Doing radix" << std::endl;
sort_selector::_radix_sort(begin, end);
}
template<typename T>
typename std::enable_if<
!std::is_integral<typename T::value_type>::value>::type
sort(T begin, T end){
std::cout << "Doing sort" << std::endl;
std::sort(begin, end);
}
}
int main(int argc, char** argv) {
std::vector<double> for_stdsort = {1, 4, 6, 2};
std::vector<int32_t> for_radixsort = {1, 4, 6, 2};
//std::array<int32_t, 4> array_for_radixsort = {1, 4, 6, 2};
sort_selector::sort(std::begin(for_stdsort), std::end(for_stdsort));
sort_selector::sort(std::begin(for_radixsort), std::end(for_radixsort));
//sort_selector::sort(std::begin(array_for_radixsort),
// std::end(array_for_radixsort));
return 0;
}
.
- .
- Vorrei essere in grado di utilizzare iteratori simili a array.(non hanno :: Value_type).
- Vorrei essere in grado di distinguere tra dire, int32_t e int64_t.
Sono a una perdita completa di come ottenere questo in qualsiasi modo ragionevolmente semplice.CioèNon specializzato per ogni istanza.
Soluzione
Utilizzare std::iterator_traits<T>::value_type
per recuperare il tipo di valore di un iteratore;Funziona per i puntatori e iteratori di tipo classe.
Per la spedizione, utilizzerei la specializzazione del modello per selezionare la corretta implementazione ( DEMO live ):
namespace sort_selector {
// Default to using std::sort
template <typename T, typename = void>
struct dispatcher {
template <typename Iterator>
static void sort(Iterator begin, Iterator end) {
std::cout << "Doing std::sort\n";
std::sort(begin, end);
}
};
// Use custom radix sort implementation for integral types
template <typename T>
struct dispatcher<T, typename std::enable_if<std::is_integral<T>::value>::type> {
template <typename Iterator>
static void sort(Iterator, Iterator) {
std::cout << "Doing radix\n";
// radix implementation
}
};
// Use some other specific stuff for int32_t
template <>
struct dispatcher<int32_t, void> {
template <typename Iterator>
static void sort(Iterator, Iterator) {
std::cout << "Specific overload for int32_t\n";
// Do something
}
};
// Dispatch appropriately
template <typename Iterator>
inline void sort(Iterator begin, Iterator end) {
dispatcher<typename std::iterator_traits<Iterator>::value_type>::sort(begin, end);
}
} // namespace sort_selector
.
Dovresti probabilmente vincolare sort_selector::sort
per richiedere iteratori di accesso casuali in modo che i tuoi messaggi di errore siano più digeribili quando qualcuno cerca inevitabilmente di superare un tipo Iteratore improprio:
namespace sort_selector {
// Dispatch appropriately
template <typename Iterator>
inline void sort(Iterator begin, Iterator end) {
using traits = std::iterator_traits<Iterator>;
static_assert(
std::is_base_of<
std::random_access_iterator_tag,
typename traits::iterator_category
>::value, "sorting requires random access iterators");
dispatcher<typename traits::value_type>::sort(begin, end);
}
} // namespace sort_selector
.