嵌套成员类型识别

时间:2012-11-22 16:12:37

标签: c++ c++11 sfinae

今天,我试图对某个类是否具有嵌套类型reverse_iterator执行类型切换。我在这些论坛上发现了一些有效的解决方案,其中包括以下内容:

template<typename T>
struct is_reverse_iterable
{
    using yes   = uint8_t;
    using no    = uint16_t;

    template<typename U>
    static yes& test(typename U::reverse_iterator*);

    template<typename>
    static no& test(...);

    static constexpr bool value = sizeof(test<T>(0)) == sizeof(yes);
};

如果我只是从main检查条件,这个类工作得很好,但是,我也写了一个小函数,这会导致一些问题。

template<typename T>
void foo(T&& iter)
{
    std::cout << typeid(T).name() << std::endl;
    std::cout << is_reverse_iterable<T>::value << std::endl;
}

这是导致我出现问题的主要原因:

int main()
{
    using namespace std;

    vector<int> v;

    cout << typeid(decltype(v)).name() << endl;
    cout << is_reverse_iterable<decltype(v)>::value << endl;

    foo(v);

    return 0;
}

由于std::vector<int>包含嵌套类型名称reverse_iterator,人们会认为 - 或者至少,我认为 - is_reverse_iterable<vector<int>>::value无论我放在哪里都会返回true。但事实并非如此。以下是主要结果:

St6vectorIiSaIiEE
1
St6vectorIiSaIiEE
0

从main调用时,结构is_reverse_iterablereverse_iterator中识别出名称vector<int>,但在从foo调用时却没有这样做。实际上,我不知道为什么,我希望有人请向我解释问题是什么:)

P.S。 :我使用MinGW g ++ 4.7.1编译,使用选项-std = c ++ 11。

1 个答案:

答案 0 :(得分:1)

问题在于,当您致电foo(v)时,会推断出T类型为std::vector<int>&左值 - 参考),因此{{ 1}}将无法编译。您可以自己轻松检查:

typename T::reverse_iterator

收率:

template<typename T>
void foo(T&& iter)
{
    std::cout << typeid(T).name() << std::endl;
    std::cout << is_reverse_iterable<T>::value << std::endl;

    typename T::reverse_iterator t;  // <-- add this line to see what's wrong
}

解决方案很简单:在启动SFINAE之前删除引用,例如

3.cpp: In instantiation of ‘void foo(T&&) [with T = std::vector<int>&]’:
3.cpp:40:10:   required from here
3.cpp:27:34: error: ‘std::vector<int>&’ is not a class, struct, or union type