检查继承函数的函数签名。

3
我需要检查容器的erase函数是否返回迭代器。通常我会通过boost等工具检查函数签名,但是对于boost类(例如flat_set),erase是继承而来的,因此无法通过检查找到。但我确实需要它。SFINAE用于检查继承的成员函数只展示了C++11的解决方案,而我目前无法使用它。
我尝试了以下代码:
    template <typename T> 
    class has_member_func_erase_it_constit
    { 
        typedef typename T::iterator iterator;
        typedef typename T::const_iterator const_iterator;
        typedef BOOST_TYPEOF_TPL(&T::erase) eraseType;

        typedef typename boost::function_types::result_type<eraseType>::type result;
    public: 
        static const bool value = boost::is_same<iterator, result>::value; 
    };

    template<class T>
    struct EraseReturnsIterator
    {
        static CONSTEXPR bool value = has_member_func_erase_it_constit<T>::value;
    };

但是它失败了,因为erase被重载了。我可能需要decltype或类似的东西来检查使用const_iterator时从编译时调用erase的返回类型,但我找不到。

在C++11之前,这怎么可能呢?

如果有一个返回void的erase函数,这也行不通:

    template <typename T> 
    class has_member_func_erase_it
    { 
        typedef typename T::iterator iterator;
        typedef typename T::const_iterator const_iterator;

        typedef char yes[1];
        typedef char no [2];

        static T makeT();
        static iterator makeIt();

        typedef BOOST_TYPEOF_TPL(makeT().erase(makeIt())) result;

    public: 
        static const bool value = boost::is_same<iterator, result>::value; 
    };

我猜你需要更具体一些;有些容器有多个名为 erase 的方法。例如,vector 同时拥有 erase(iterator)erase(iterator, iterator) 两种方法。 - Marshall Clow
你在升级到C++11之前会遇到多少个容器?10个?硬编码它们。如果定义了C++11,就做正确的事情,也许断言它们是一致的。 - Yakk - Adam Nevraumont
我的意思是检查“void erase(iterator)”和“iterator erase(iterator)”之间的区别。但我找到了一个可行的解决方案,今天稍后会发布它。这是一些非常好的邪恶模板技巧。 - Flamefire
1个回答

0

以下代码可正常运行:

    /// "Stores a type"
    template<typename T> struct Type2Type{
        typedef T type;
    };

    /// Evil hackery to put an expression into a type
    template<typename T>
    Type2Type<T> operator,(T, Type2Type<void>);

    template<typename T>
    T declval();

    template<class T>
    struct EraseReturnsIterator
    {
        typedef typename T::iterator iterator;
        typedef BOOST_TYPEOF_TPL((declval<T>().erase(declval<iterator>()), Type2Type<void>())) result;

        static CONSTEXPR bool value = boost::is_same<iterator, typename result::type>::value;
    };

基本上,我们只需调用返回所需返回类型的函数。如果此类型的任何函数都没有返回void,则BOOST_TYPEOF_TPL将已经起作用。不幸的是,erase可以返回void,这会破坏实现,因为它试图将“void&”传递到堆栈下方。

因此,为了避免void(无意冒犯),我们将其放在一个包含类型的类型中。为了能够对表达式执行此操作,我们重载了逗号运算符。这样,结果等于“Type2Type”,我们可以轻松地阅读。完成!

逗号重载的想法:https://dev59.com/71LTa4cB1Zd3GeqPeu2D#5553460


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接