4 votes

Pourquoi avons-nous une inadéquation de type ?

J'ai écrit un programme pour voir, comment littéraux de chaîne de caractères ont été déduites dans les fonctions de modèle.

#include <iostream>
#include <string>
#include <type_traits>

template<typename T> void passByValue(T by_value)
{
    std::cout << std::is_same_v<char const*, decltype(by_value)> << std::endl; // okay
}

template<typename T> void passByReferance(T &by_ref)
{
    std::cout << std::is_same_v<char const*, std::remove_reference_t<decltype(by_ref)>> << std::endl;
}

template<typename T> void passByConstRef(const T &const_ref)
{
    std::cout << std::is_same_v<char const*, std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>> << std::endl;
}

int main()
{
    std::cout << std::boolalpha;
    passByValue("string");    // true: good
    passByReferance("string");// false ??
    passByConstRef("string"); // false ??
    return 0;
}

Il s'avère que, seulement pour le passByValue les littéraux de chaîne déduits à const char* type.

Dans les deux autres cas( passByReferance y passByConstRef ), si l'on applique aux arguments déduits, std::remove_reference_t y std::remove_const_t ce que je suis censé obtenir est const char* Est-ce exact ?

J'obtiens une correspondance de type lorsque je fais une désintégration complète en utilisant std::decay_t Pourquoi ?

7voto

François Andrieux Points 16034

Vous passez const char[7] no const char * . Les tableaux et les pointeurs ne sont pas les mêmes choses. Ils sont souvent confondus parce que les tableaux se transforment facilement en pointeurs à leur premier élément. Lorsqu'ils sont pris par référence, les tableaux n'ont pas besoin de se transformer en pointeurs. Ce n'est que dans le premier cas que votre tableau doit se transformer en pointeur.

Les tests suivants produisent true pour chaque cas :

#include <iostream>
#include <string>
#include <type_traits>

template<typename T> void passByValue(T by_value)
{
    std::cout << std::is_same_v<char const*, decltype(by_value)> << std::endl; 
}

template<typename T> void passByReferance(T &by_ref)
{
    std::cout << std::is_same_v<char const[7], std::remove_reference_t<decltype(by_ref)>> << std::endl;
}

template<typename T> void passByConstRef(const T &const_ref)
{
    std::cout << std::is_same_v<char [7], std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>> << std::endl;
}

int main()
{
    std::cout << std::boolalpha;
    passByValue("string");    
    passByReferance("string");
    passByConstRef("string"); 
    return 0;
}

Edit : Quant à std::decay il fait explicitement en sorte que les types de tableaux se transforment en pointeurs :

Si T nomme le type "tableau de U "ou "référence à un tableau de U ", le type de membre typedef est U* .

2voto

balki Points 4786

Quelques aides pour avoir une meilleure vue des types. CE : https://godbolt.org/z/6EFmIR

#include <type_traits>

template<class T>
struct Tis { Tis(); };

template<bool b>
struct Truth{ Truth(); };

template<typename T> void passByValue(T by_value)
{
    Tis<T>{}; //call    Tis<char const*>::Tis()
    Truth<
        std::is_same_v<char const*, decltype(by_value)>
    >{}; // call    Truth<true>::Truth()
}

template<typename T> void passByReferance(T &by_ref)
{
    Tis<T>{}; // call    Tis<char const [7]>::Tis()
    Tis<decltype(by_ref)>{}; // call    Tis<char const (&) [7]>::Tis()
    Truth<
        std::is_same_v<char const*, std::remove_reference_t<decltype(by_ref)>> 
    >{}; // call    Truth<false>::Truth()
    Tis<
        std::remove_reference_t<decltype(by_ref)>
    >{}; // call    Tis<char const [7]>::Tis()
}

template<typename T> void passByConstRef(const T &const_ref)
{
    Tis<T>{}; // call    Tis<char [7]>::Tis()
    Truth<
        std::is_same_v<char const*, std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>> 
    >{}; // call    Truth<false>::Truth()
    Tis<
        std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>
    >{}; // call    Tis<char [7]>::Tis()
}

void foo1(){
    passByValue("string");
}
void foo2() {
    passByReferance("string");
}
void foo3() {
    passByConstRef("string");
}

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