ADL在特定情况下不起作用

ADL does not work in the specific situation

本文关键字:不起作用 在特定情况下 ADL      更新时间:2023-10-16

我制作了如下的is_iterable模板,它检查自由函数begin/end是否可用(在ADL的上下文中)并返回正确的迭代器对象。(这是对循环范围内可迭代对象的要求)

#include <utility>
#include <iterator>
#include <type_traits>
#include <vector>
template <typename T>
typename std::add_rvalue_reference<T>::type declval(); // vs2010 does not support std::declval - workaround
template <bool b>
struct error_if_false;
template <>
struct error_if_false<true>
{
};
template<typename U>
struct is_input_iterator
{
    enum {
        value = std::is_base_of<
            std::input_iterator_tag,
            typename std::iterator_traits<U>::iterator_category
        >::value
    };
};
template<typename T>
struct is_iterable
{
    typedef char yes;
    typedef char (&no)[2];
    template<typename U>
    static auto check(U*) -> decltype(
        error_if_false<
            is_input_iterator<decltype(begin(declval<U>()))>::value
        >(),
        error_if_false<
            is_input_iterator<decltype(end(declval<U>()))>::value
        >(),
        error_if_false<
            std::is_same<
                decltype(begin(declval<U>())),
                decltype(end(declval<U>()))
            >::value
        >(),
        yes()
    );
    template<typename>
    static no check(...);
public:
    static const bool value = (sizeof(check<typename std::decay<T>::type>(nullptr)) == sizeof(yes));
};
#include <cstdio>
void write(int a)
{
    printf("%dn", a);
}
template<typename T>
typename std::enable_if<is_iterable<T>::value>::type write(const T& a)
{
    for (auto i = begin(a), e = end(a); i != e; ++i) {
        write(*i);
    }
}
int main()
{
    write(10);
    std::vector<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    a.push_back(4);
    write(a);
}

上面的代码在vs2010中完全按照预期工作,但在gcc中则不然。此外,当我放入一些名为"begin"的随机自由函数时,如下所示,它在vs2010中变得盈亏平衡。

int begin(int)
{
}

如何使代码正常工作?此外,任何改进"is_iterable"概念检查器的建议都将不胜感激。

added:"write"函数只是一个概念演示示例,请不要在上面投入宝贵的时间。(我知道这不是最好的代码:()需要注意的部分是ADL行为和"is_iterable"模板:)

std::添加到begin/end之后,您的代码将在gcc-4.6 下编译和运行

改进建议:将error_if_false替换为enable_if

write(a);应该像Jerry所说的那样通过运算符来定义。也许可以让它更加深思熟虑,这样你的代码就更干净了。