0
votes

choix de la fonction à la compilation en fonction de la taille du type

Je voudrais avoir une fonction de modèle pour copier des données d'une manière spéciale. Il existe un moyen simple si la taille du type d'élément de données est un multiple de 4 octets, c'est-à-dire (sizeof (T)% 4 == 0):

template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount);

et il existe une manière plus complexe de copier le tableau si ce n'est pas le cas:

template <typename T, typename Idx, uint32 dimensions>
void loadDataNo4BWords(T *target, const T *source, const Idx eleCount);


2 commentaires

Quelle version C ++ est disponible?


L'intersection de ce qui est pris en charge par GCC 7 et MSVC 19.23.


4 Réponses :


4
votes

Vous pouvez utiliser if constexpr depuis C ++ 17 pour appeler l'un ou l'autre:

template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount) {
    if constexpr(sizeof(T) % 4 == 0)
        loadData4BWords<T, Idx, dimensions>(target, source, eleCount);
    else
        loadDataNo4BWords<T, Idx, dimensions>(target, source, eleCount);
}

Contrairement à if , si constexpr est testé au moment de la compilation et seule la branche correspondante est compilée.


1 commentaires

Merci pour votre réponse rapide et cette belle solution! :)



0
votes

Vous pouvez faire de la fonction un membre d'une structure et utiliser une spécialisation partielle de modèle:

load_data<3>(dest, src, index);

et l'appel serait alors:

template<typename T, bool is_even_multiple=0==(sizeof(T)%4)>
struct load_data_helper;

template<typename T>
struct load_data_helper<T, true>
{
template<uint32_t Dimensions, typename Idx>
static void apply(T * dest, T const * src, Idx const & index)
{ ... }
};
template<typename T>
struct load_data_helper<T, false>
{
template<uint32_t Dimensions, typename Idx>
static void apply(T * dest, T const * src, Idx const & index)
{ ... }
};

template<uint32_t Dimensions, typename T, typename Idx>
void load_data(T * dest, T const * src, Idx const & index)
{
load_data_helper<T>::apply<Dimensions>(dest, src, index);
}

Notez que je n'ai pas compilé ce qui précède, il peut donc y avoir des erreurs dans le code fourni, mais la méthode décrite devrait fonctionner.


1 commentaires

Merci pour la réponse rapide! J'irais pour une telle solution si je ne pouvais pas utiliser constexpr si.



1
votes

si constexpr est le meilleur. Mais la distribution de balises old school fonctionne aussi, et peut-être que cela pourrait être plus clair dans certains cas (en particulier avant C ++ 17), je vais donc contribuer cette option à la discussion:

template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount, std::true_type)
{
    loadData4BWords(target, source, eleCount);
}

template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount, std::false_type)
{
    loadDataNo4BWords(target, source, eleCount);
}

template <typename T, typename Idx, uint32 dimensions>
void loadData(T *target, const T *source, const Idx eleCount)
{
    loadData(target, source, eleCount,
        std::integral_constant<bool, sizeof(T) % 4 == 0>{});
}


0 commentaires

0
votes

En C ++ 17 if constexpr , comme suggéré par uneven_mark, est la solution la plus simple et la plus claire (IMHO).

Avant C ++ 17 (C ++ 11 et C ++ 14) vous pouvez utiliser la surcharge et SFINAE (avec std::enable_if)

Je veux dire ... vous pouvez simplifier beaucoup le problème si, à la place, un loadData4BWords ( ) et une fonction loadDataNo4BWords () jamais activée, vous créez un loadData () activé uniquement lorsque 0u == sizeof (T)% 4u (équivalent à loadData4BWords () ) et un loadData () activé uniquement lorsque 0u! = sizeof (T)% 4u ( loadDataNo4BWords () équivalent).

Ce qui suit est un exemple de travail complet en C ++ 11 (simplifié: un seul paramètre)

template <typename T>
std::enable_if_t<0u == sizeof(T) % 4u> loadData (T *)
 { std::cout << "4 version" << std::endl; }

template <typename T>
std::enable_if_t<0u != sizeof(T) % 4u> loadData (T *)
 { std::cout << "no 4 version" << std::endl; }

En C ++ 14 (et C ++ 17, si vous le souhaitez) vous pouvez utiliser std :: enable_if_t pour simplifier un peu

#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<0u == sizeof(T) % 4u>::type loadData (T *)
 { std::cout << "4 version" << std::endl; }

template <typename T>
typename std::enable_if<0u != sizeof(T) % 4u>::type loadData (T *)
 { std::cout << "no 4 version" << std::endl; }


int main ()
 {
   char  ch;
   int   i;

   loadData(&ch);
   loadData(&i);
 }

ps: voir aussi le mode de répartition des tags dans la réponse de Jeff Garrett.


0 commentaires