Я написал программу, чтобы увидеть, как строковые литералы выводится в шаблонных функциях.
#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;
}
Получается, что только для пройти по значению строковые литералы приведены к типу const char*.
В двух других случаях (PassByReference и пройтиByConstRef), если мы применим к выведенным аргументам, std::remove_reference_t и std::remove_const_t, я полагаю, что мы получим const char*, это правильно?
Я получаю совпадение типов, когда делаю полное затухание с помощью std::decay_t, почему?
@balki Это хорошо: ваш код демонстрирует вид машины. Не могли бы вы опубликовать его в разделе ответов? По крайней мере, я могу дать вам большой палец вверх.





Вы передаете 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, это явно приводит к тому, что типы массивов распадаются на указатели:
If
Tnames the type "array ofU" or "reference to array ofU", the member typedef type isU*.
то что происходит в случае применение std::decay_t
@JoeyMallone Не используйте простые массивы, и вам никогда не придется об этом беспокоиться. std::array и std::string/std::string_view должно хватить.
@MaxLanghof, да, спасибо. Я узнаю что-то новое, каждый день здесь.
@Const Переместил мой комментарий в ответ.
@FrançoisAndrieux Да, это правда, я все время думал, что std::decay делает его const char*, но те, которые я использовал, нет. Это проясняет мои сомнения. Спасибо.
Некоторые помощники, чтобы лучше видеть типы. 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");
}
Ответ охватывает все детали. Если вам нужна лучшая видимость типов, вы можете использовать помощники здесь: godbolt.org/z/AqTA0e