Я знаю, что контейнеры STL имеют параметр value_type, и я видел, как его можно использовать для объявления типа переменной, например:
vector<int>::value_type foo;
Но можем ли мы просто распечатать этот value_type на консоли?
Я хочу увидеть в этом примере «строку»:
int main() {
vector<string> v = {"apple", "facebook", "microsoft", "google"};
cout << v << endl;
cout << v.value_type << endl;
return 0;
}
это просто тип, поэтому вы хотите получить имя типа в виде строки?
Вполне возможно, но вам нужно добавить код.
Это было бы эквивалентно cout << string;, а это не то же самое, что cout << "string";.
да @molbdnilo я хочу тип в виде читаемой человеком строки
Возможный дубликат Шаблон, который печатает имя данного типа





X::value_type ничем не отличается от любого другого псевдонима типа (также известного как typedef) в этом отношении - C++ не имеет собственного способа преобразования типа в его строковое представление исходного кода (не в последнюю очередь потому, что это может быть неоднозначным). Что вы можете сделать, так это использовать std::type_info::name:
cout << typeid(decltype(v)::value_type).name() << endl;
Результирующий текст зависит от компилятора (и даже не гарантируется, что он будет легко читаемым человеком). Он будет согласован в одной и той же сборке программы, но нельзя ожидать, что он будет одинаковым для разных компиляторов. Другими словами, он полезен для отладки, но не может надежно использоваться постоянно.
Спасибо, на моей машине дает NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
@ Вы можете использовать __cxa_demangle, чтобы получить читаемое имя типа: stackoverflow.com/a/23266701/1968
Разве это не только для gcc?
@Niakrais: Не совсем, это для всех комбинаций компиляторов / платформ, использующих Itanium ABI. Itanium ABI используется на всех платформах Linux / MacOS всеми распространенными компиляторами C++; единственная широко распространенная платформа, не использующая его, - это Windows, и поэтому MSVC и Clang в режиме совместимости с MSVC не будут использовать его. Даже в Windows использование Cygwin или MinGW означает использование Itanium ABI.
В дополнение к ответу на основе typeid я вижу еще одну возможность использования Boost следующим образом:
#include <boost/type_index.hpp>
cout << boost::typeindex::type_id_with_cvr<decltype(v)::value_type>().pretty_name() << "\n";
Преимущество - портативное, удобочитаемое имя, которое включает в себя квалификацию const / volatile и согласовано во всех основных компиляторах и системах. Результат на моей машине
// when compiled with gcc:
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
// ... and with clang:
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
Решите для себя, можно ли считать этот вывод «читаемым человеком», но также сравните его с подходом typeid(...).name(), который на моей машине дает:
NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
Наверное, это можно с уверенностью предположить, что вам нужна эта информация о типе для целей отладки (?).
Если это так, не забудьте встроенные в GDB команды whatis и ptype:
$ cat main.cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<string> v = {"apple", "facebook", "microsoft", "google" };
cout << v[2] << endl;
// cout << v.value_type << endl;
return 0;
}
$ cat gdbCommands.txt
break main
run
next
next
whatis v
quit
$ g++ -ggdb -o main main.cpp
$ gdb -x gdbCommands.txt ./main
GNU gdb (Ubuntu 8.0.1-0ubuntu1) 8.0.1
// bla bla bla ...
type = std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >>
Некоторое время назад у меня был довольно аналогичный вопрос. Ответ там показал функцию, способную переводить тип в удобочитаемую строку:
template <typename T> std::string TypeName() {
auto name = typeid(T()).name(); // function type, not a constructor call!
int status = 0;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
std::string ret((status == 0) ? res.get() : name);
if (ret.substr(ret.size() - 3) == " ()") ret.resize(ret.size() - 3);
return ret;
}
Когда у вас есть эта функция TypeName, вы можете достичь своей цели:
int main() {
vector<string> v = {"apple", "facebook", "microsoft", "google" };
cout << v << endl;
cout << TypeName<v.value_type>() << endl;
return 0;
}
Что должно вывести (GCC HEAD 9 201809):
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
Если это для целей отладки, то это решение будет работать без каких-либо зависимостей:
#include <regex>
template <typename T>
struct TypeToNameT
{
static std::string getTypeFromName() {
#ifdef _MSC_VER
std::regex re("<(.*)>::.*");
std::string templateType(__FUNCTION__);
#else
std::regex re(" = (.*);");
std::string templateType(__PRETTY_FUNCTION__);
#endif
std::smatch match;
try
{
if (std::regex_search(templateType, match, re) && match.size() > 1)
return match.str(1);
}
catch (std::regex_error& e) {
// Syntax error in the regular expression
}
return "";
}
};
/** Get the templated type name. This does not depends on RTTI, but on the preprocessor, so it should be quite safe to use even on old compilers */
template <typename T>
std::string getTypeName() { return TypeToNameT<T>::getTypeFromName(); }
int main() {
std::vector<std::string> v = {"apple", "facebook", "microsoft", "google" };
std::cout << getTypeName<decltype(v)::value_type>() << std::endl; // Returns: "std::__cxx11::basic_string<char>"
return 0;
}
В отличие от ответа на основе typeid, здесь используется препроцессор, и поэтому он не подлежит изменению имени (поэтому имя ... удобочитаемый).
Обратите внимание, что вы не можете использовать v.value_type как тип напрямую, он не является частью экземпляра v, а относится к типу v: std::vector<std::string>
Часть с регулярным выражением связана с тем, что класс std::string слишком тупой, и вам нужны такие странности для простого кода поиска / разделения. Если у вас есть достойный строковый класс, вам не понадобится здесь регулярное выражение для извлечения части, которая находится после строки "=" и перед ";".
__FUNCTION__ печатает только имя функции без какой-либо дополнительной информации. Вам нужен __FUNCSIG__.
Просто попробовал вот здесь: rextester.com/FDZT51977 и вроде работает с НАЗНАЧЕНИЕ. При использовании FUNCSIG регулярное выражение должно быть изменено, поскольку подпись более сложна. Во всех случаях спасибо, я раньше не знал о FUNCSIG.
Да ладно, ты прав. __FUNCTION__ не содержит шаблонных параметров самой функции, поэтому, когда я использовал этот трюк раньше, я прибегал к использованию __FUNCSIG__. Но мне не хватало того, что он содержит параметры шаблона включающих классов. Хорошая идея.
Символ
value_typeне является переменной-членом, это имя типа с ограниченной областью видимости. Ожидаете ли вы, что сможете распечатать значение ключевого словаint?