本文介绍了使用SFINAE检测某物是否在(增强)范围内的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于日志记录代码,我想检测是否可以使用 Boost.Range 与否.显然,无论是否需要实例化不同的代码,因此我都需要SFINAE,可能(当然可以)与boost :: enable_if结合使用.我尝试检测是否定义了 begin end 自由函数,如下所示:

For logging code, I would like to detect whether given argument to a template function can be iterated over using the tools from Boost.Range or not. Obviously I need to instantiate different code whether it is or not, so I need SFINAE, possibly (well, certainly) combined with boost::enable_if. I've tried detecting whether begin and end free functions are defined, like this:

namespace is_range_impl {
    template <typename T> T &make();
    struct any { template <class T> any(T const&); };
    struct not_range {};
    not_range begin(const any &);
    not_range end(const any &);
    struct no_type { char x[8]; };
    typedef char yes_type;
    template <typename T> yes_type check(const T &t);
    no_type check(const not_range &t);
    using boost::begin;
    using boost::end;
    template <typename T> struct is_range_impl {
        enum e {
            value = (sizeof(check(begin(make<T>()))) == sizeof(yes_type) &&
                     sizeof(check(end(make<T>()))) == sizeof(yes_type)),
        };
    };
}

template <typename T>
struct is_range : public is_range_impl::is_range_impl<T> {};

template <typename T>
typename boost::disable_if<is_range<T> >::type repr(std::ostream &s, const T &v)
{ ... }

template <typename T>
typename boost::enable_if<is_range<T> >::type repr(std::ostream &s, const T &v)
{ ... }

但是当未正确定义 boost :: begin boost :: end 时,它不会默默地失败,而是大声地失败并显示错误消息

But instead of silently failing when boost::begin and boost::end are not well-defined, it fails loudly with error that

'type' : is not a member of 'boost::mpl::eval_if_c<C,F1,F2>'
    [C=false, F1=boost::range_const_iterator<void *>, F2=boost::range_mutable_iterator<void *>]

在以下代码中的 boost/range/iterator.hpp:63 中:

typedef BOOST_RANGE_DEDUCED_TYPENAME
        mpl::eval_if_c< is_const<C>::value,
                        range_const_iterator< typename remove_const<C>::type >,
                        range_mutable_iterator<C> >::type type;

(我提高了1.51,但1.52没有列出任何更改,而1.53 alpha列出了两个错误修复,但似乎都没有关系)

(I have boost 1.51, but 1.52 lists no changes and 1.53 alpha lists two bug-fixes, but neither seems to be related)

那么,有什么更好的方法来检测距离吗?虽然我仍停留在某些C ++ 03编译器上,并且可能会花相当长的时间,但我想使其能够轻松切换到C ++ 11(其中免费的 begin 和 end 似乎就足够了.

So is there some better way to detect ranges? While I am stuck with some C++03 compilers and probably will be for quite a long while longer, I would like to make it as easily switchable to C++11 (where free begin and end available via ADL appear to be all that's needed).

具体来说,编译器是Visual C ++ 9.0和GCC 4.5.SFINAE的支持都足够.

Specifically the compilers are Visual C++ 9.0 and GCC 4.5. SFINAE support is adequate in both.

推荐答案

我相信您需要使用的元函数是 has_range_iterator .

I believe the metafunction you need to use is has_range_iterator.

在LWS上运行

#include <iostream>
#include <string>
#include <utility>

#include <boost/range.hpp>

template <typename T>
typename boost::disable_if<boost::has_range_iterator<T> >::type repr(const T &, const std::string& name)
{ std::cout << name << " is not a range" << std::endl; }

template <typename T>
typename boost::enable_if<boost::has_range_iterator<T> >::type repr(const T &, const std::string& name)
{ std::cout << name << " is a range" << std::endl; }

struct foo{};
struct bar
{
   typedef int iterator;
    typedef const int const_iterator;
    int begin(){ return 0;};
    int end(){ return 1;};
};


int main()
{
    int i;
    repr(i, "int");
    int array[10];
    repr(array, "int array");
    std::string str;
    repr(str, "std::string");
    foo f;
    repr(f, "foo");
    bar b;
    repr(b, "bar");

    std::pair<int, int> p;
    repr(p, "pair"); // it does make a mistake here, because std::pair<int, int> looks like range, but int is not valid iterator (cannot be dereferenced)
}

这篇关于使用SFINAE检测某物是否在(增强)范围内的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 17:40