Почему у нас несоответствие типов? - PullRequest
0 голосов
/ 30 января 2019

Я написал программу, чтобы увидеть, как строковые литералы выводятся в шаблонных функциях.

#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;
}

Оказывается, что только для passByValue строковые литералы выводятся в тип const char*.

В двух других случаях ( passByReferance и passByConstRef ), если мы применим к выведенным аргументам, std::remove_reference_t и std::remove_const_t, что мы предполагаем получитьэто const char*, это правильно?

Я получаю совпадение типов, когда завершаю распад, используя std::decay_t, почему это так?

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Некоторые помощники, чтобы лучше видеть типы.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");
}
0 голосов
/ 30 января 2019

Вы передаете const char[7], а не const char *.Массивы и указатели - это не одно и то же.Они часто путаются, потому что массивы легко распадаются на указатели на их первый элемент.При использовании по ссылке массивы не должны распадаться на указатели.Только в первом случае ваш массив должен распадаться на указатель.

Следующие тесты выдают true для каждого случая:

#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;
}

Редактировать: Как для std::decay, это явно приводит к тому, что типы массивов распадаются на указатели:

Если T называет тип "массив из U" или "ссылка на массив из U",член typedef типом является U*.

...