我们如何打印C ++ STL容器的value_type?

时间:2018-09-03 09:06:08

标签: c++ stl

我知道STL容器具有一个val hostViews = arrayListOf<FrameLayout>() // Member variable of MainActivity hostViews.apply { add(findViewById(R.id.frame_dog)) add(findViewById(R.id.frame_cat)) } 参数,并且我已经看到如何使用它来声明变量的类型,例如:

hostViews

但是我们可以只将此value_type打印到控制台吗?

我想在此示例中看到“字符串”:

vector<int>::value_type foo;

5 个答案:

答案 0 :(得分:15)

在这方面,

X::value_type与任何其他类型别名(也称为typedef)没有什么不同-C ++没有将类型转换为其源代码字符串表示形式的本地方法(这至少是不明确的)。您可以使用std::type_info::name

cout << typeid(decltype(v)::value_type).name() << endl;

结果文本取决于编译器(甚至不能保证易于阅读)。在同一程序的内部版本中,它是一致的,但是您不能期望它在不同的编译器中是相同的。换句话说,它对于调试很有用,但不能可靠地持久使用。

答案 1 :(得分:5)

除了基于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

答案 2 :(得分:1)

假定您出于调试目的需要此类型信息可能很安全(?)。 如果是这样,请不要忘记gdb内置的whatisptype命令:

$ 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> >>

答案 3 :(得分:1)

前段时间我有一个similar question。那里的答案显示了一个能够将类型转换为人类可读字符串的函数:

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> >

答案 4 :(得分:1)

如果用于调试目的,则此解决方案将在没有任何依赖性的情况下工作:

function render_flat_nav($categories) {
    $html = '<ul>';
    foreach($categories as $category) {
        $html .= '<li>('.$category->getId().') '.utf8_decode($category->getName()) . "\n";
        if($category->hasChildren()) {
            $children = Mage::getModel('catalog/category', array('disable_flat' => true))->getCategories($category->entity_id);
            $html .= render_flat_nav($children);
        }
        $html .= '</li>';
    }
    return $html . '</ul>';
}

与基于#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>类太笨了,对于简单的搜索/拆分代码,您需要这些奇怪的东西。如果您有一个不错的字符串类,则这里不需要正则表达式来提取“ =”字符串之后和“;”之前的部分。