2 votes

Obtenir le niveau du pointeur à partir du type plutôt que de la variable

J'essaie de faire en sorte qu'il soit possible d'afficher la profondeur du pointeur sous forme d'un nombre entier d'astérisques - par exemple int*** serait 3 . Mais au lieu de le calculer à partir du type, j'ai écrit un code qui exige que chaque niveau de pointeur soit correctement initialisé. Voici ce que j'ai essayé :

#include <iostream>
#include <utility>

// no pointers involved
template <class T>
std::size_t get_pointer_level(T)
{
    return 0;
}

// final value reached, returning depth
template <class T>
std::size_t get_pointer_level(std::pair<std::size_t, T> arg)
{
    return arg.first;
}

// function that accummulates depth
template <class T>
auto get_pointer_level(std::pair<std::size_t, T*> arg)
{
    return get_pointer_level(std::make_pair(arg.first+1, *arg.second));
}

// initial function called for pointer argument
template <class T>
auto get_pointer_level(T* arg)
{
    return get_pointer_level(std::make_pair(std::size_t(1), *arg));
}

int main(void)
{
    int a = 10;
    auto b = &a; //int*
    auto c = &b; //int**
    auto d = &c; //int***
    auto e = &d; //int****
    std::cout << get_pointer_level(e) << std::endl; //4
}

Je suis presque sûr qu'il est tout à fait possible de le faire fonctionner en utilisant uniquement la typographie. J'imagine que la syntaxe serait quelque chose comme ça :

get_pointer_level<int****>::value

Des idées ?


EDIT : Merci pour la solution ! Voici la fonctionnalité finale que je voulais accomplir :

template <std::size_t A, std::size_t B>
struct is_smaller
{
    enum {value = (A < B)? 1 : 0};
};
template<std::size_t Target, typename T, std::size_t Actual = get_pointer_level<T>::value>
T value_at_level(T pointer)
{
    static_assert(Actual==Target, "Invalid target level!");
    return pointer;
}

template<std::size_t Target, typename T, std::size_t Actual = get_pointer_level<T*>::value,
         typename = std::enable_if<is_smaller<Target, Actual>::value>::type>
auto value_at_level(T* pointer)
{
    return value_at_level<Target>(*pointer);
}

int main()
{
    int a = 5;
    auto b = &a; //int*
    auto c = &b; //int**
    auto d = &c; //int***
    auto e = &d; //int****

    std::cout << "int from int****: " << value_at_level<0>(e) << std::endl; //ok
    std::cout << "int* from int***: " << value_at_level<1>(d) << std::endl; //ok
    std::cout << "int** from int**: " << value_at_level<2>(c) << std::endl; //ok
    std::cout << "int*** from int*: " << value_at_level<3>(b) << std::endl; //error
    std::cout << "int**** from int: " << value_at_level<5>(a) << std::endl; //error
}

9voto

milleniumbug Points 4445

Un exercice de spécialisation partielle :

#include <cstddef>

template<typename T, std::size_t S>
struct get_pointer_level_impl
{
    static const std::size_t value = S;
};

template<typename T, std::size_t S>
struct get_pointer_level_impl<T*, S> : get_pointer_level_impl<T, S+1>
{

};

template<typename T>
struct get_pointer_level : get_pointer_level_impl<T, 0>
{

};

#include <iostream>

int main()
{
    std::cout << get_pointer_level<int>::value << "\n";
    std::cout << get_pointer_level<int*>::value << "\n";
    std::cout << get_pointer_level<int**>::value << "\n";
    std::cout << get_pointer_level<int***>::value << "\n";
}

Sortie :

0
1
2
3

8voto

Miles Budnek Points 9709

Si vous êtes d'accord pour l'appeler comme get_pointer_level<int*>() au lieu de get_pointer_level<int*>::value alors une récursive constexpr fonctionne très bien :

#include <iostream>
#include <type_traits>

template <typename T>
constexpr int get_pointer_level()
{
    return !std::is_pointer<T>::value ? 0 : 1 + get_pointer_level<typename std::remove_pointer<T>::type>();
}

int main() {
    std::cout << get_pointer_level<int>() << '\n';
    std::cout << get_pointer_level<int*>() << '\n';
    std::cout << get_pointer_level<int**>() << '\n';
    std::cout << get_pointer_level<int***>() << '\n';
    std::cout << get_pointer_level<int****>() << '\n';
}

DÉMO EN DIRECT

4voto

R Sahu Points 24027

Utilisez une classe d'aide pour déterminer le niveau du pointeur.

#include <iostream>

template <class T> struct PointerLevel
{
   static const std::size_t value = 0;
};

template <class T> struct PointerLevel<T*>
{
   static const std::size_t value = PointerLevel<T>::value + 1;
};

// no pointers involved
template <class T>
std::size_t get_pointer_level(T)
{
   return PointerLevel<T>::value;
}

int main(void)
{
   int a = 10;
   auto b = &a; //int*
   auto c = &b; //int**
   auto d = &c; //int***
   auto e = &d; //int****
   std::cout << get_pointer_level(a) << std::endl;
   std::cout << get_pointer_level(b) << std::endl;
   std::cout << get_pointer_level(c) << std::endl;
   std::cout << get_pointer_level(d) << std::endl;
   std::cout << get_pointer_level(e) << std::endl; //4
}

Sortie :

0
1
2
3
4

1voto

Que pensez-vous de l'utilisation de typeid(votre type).name() ?

std::string s( typeid(int***).name()); 
size_t n = std::count(s.begin(), s.end(), "*");

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X