在编译时获取表达式类型

时间:2016-09-22 09:00:49

标签: c++ c++11 c++14

使用auto关键字进行编程时,有时可以方便地了解编译器在编译时使用的类型。如果编译中止我需要知道的类型并不重要。简单的例子:

std::vector< int > s{1, 2, 3}; 

for (auto elem : s) {
    elem = 5;
}   

for (auto elem : s) {
    std::cout << elem << std::endl;
}   

将打印

1
2
3

因为elem的类型为int,而不是int&。尝试编译代码并获得elem类型以便及早发现错误会很好。

2 个答案:

答案 0 :(得分:5)

经典的方法是在没有定义的情况下声明模板结构:

template <typename> struct Debug;

然后使用它:

template struct Debug<std::string>;

for (auto elem : s) {
    Debug<decltype(elem)>{};

    elem = 5;
}

消息错误看起来像

error: explicit instantiation of 'struct Debug<std::__cxx11::basic_string<char> >' before definition of template
 template struct Debug<std::string>;
                 ^~~~~~~~~~~~~~~~~~

error: invalid use of incomplete type 'struct Debug<int>'
         Debug<decltype(e)>{};

Demo

BTW,现在有些IDE会在鼠标超过auto或变量时显示类型。

答案 1 :(得分:1)

其实我刚刚找到了自己问题的答案:

template<typename T>
void show_type_abort_helper()
{
    return __PRETTY_FUNCTION__;
}

#define show_type_abort(x) show_type_abort_helper< decltype(x) >()

用法:

std::vector< int > s{1, 2, 3};

for (auto elem : s) {
    show_type_abort(elem);
    elem = 5;
}

使用g++(版本6.1.1)生成以下错误消息:

$ g++ test.cpp
test.cpp: In instantiation of ‘void show_type_abort_helper() [with T = int]’:
                                                                       ^^^
test.cpp:17:9:   required from here
test.cpp:7:12: error: return-statement with a value, in function returning 'void' [-fpermissive]
    return __PRETTY_FUNCTION__;

检查T = int处的输出,看看编译器使用int作为类型。这似乎也适用于clang:

$ clang++-3.8 -std=c++11 test.cpp
test.cpp:7:5: error: void function 'show_type_abort_helper' should not return a value [-Wreturn-type]
    return __PRETTY_FUNCTION__;
    ^      ~~~~~~~~~~~~~~~~~~~
test.cpp:17:9: note: in instantiation of function template specialization 'show_type_abort_helper<int>' requested here
                                                                                                  ^^^
        show_type_abort(elem);

更改为for (const auto& elem : s)给出

with T = const int&
         ^^^^^^^^^^

show_type_abort_helper<const int &>
                       ^^^^^^^^^^^

所以我似乎可以在编译时找出类型并中止。这对于一个非常复杂的类型来说非常方便,它由几个typedef和模板参数组成,我只是看不到发生了什么。