c++ - SFINAE 在创建 "is_iterable"特征时出现问题 - 这是 gcc 错误吗?

标签 c++ visual-studio gcc clang traits

下面的代码尝试(不使用 c++11)创建一个特征来识别一个类型是否以 STL 方式可迭代:

#include <iostream>
#include <vector>

template<typename C>
struct IsIterable
{
    typedef char true_type; 
    typedef long false_type; 

    template<class T> static true_type  is_beg_iterable(
        typename T::const_iterator = C().begin()); 
    template<class T> static false_type is_beg_iterable(...); 

    enum { value = sizeof(is_beg_iterable<C>()) == sizeof(true_type) }; 
};

int main() {
    std::cout << IsIterable<std::vector<int>>::value << std::endl;
}

还有一个is_end_iterable方法,这里为了简洁省略

代码 fails使用 gcc 4.9.2 *(以及旧版本)和 clang 并在 VS2012 中成功。我的断言是可变参数版本在重载决策中总是排在最后(因此应该没有歧义),所以谁在这儿?

是否有跨平台的解决方法/替代方案?

我现在看到较新版本的 VS 也拒绝代码,所以最后一个问题变得更重要了

最佳答案

自 C++17 起,一种定义 is_iterable 的惯用方式特征是:

#include <type_traits>
#include <iterator>

namespace is_iterable_impl
{
    using std::begin, std::end;

    template<class T>
    using check_specs = std::void_t<
        std::enable_if_t<std::is_same_v<
            decltype(begin(std::declval<T&>())), // has begin()
            decltype(end(std::declval<T&>()))    // has end()
        >>,                                      // ... begin() and end() are the same type ...
        decltype(*begin(std::declval<T&>()))     // ... which can be dereferenced
    >;

    template<class T, class = void>
    struct is_iterable
    : std::false_type
    {};

    template<class T>
    struct is_iterable<T, check_specs<T>>
    : std::true_type
    {};
}

template<class T>
using is_iterable = is_iterable_impl::is_iterable<T>;

template<class T>
constexpr bool is_iterable_v = is_iterable<T>::value;

Live demo .


我们是std::declval<T&>()所以我们的特征适用于数组。如您所见, std::begin std::end有一个数组重载,它需要一个引用。

关于c++ - SFINAE 在创建 "is_iterable"特征时出现问题 - 这是 gcc 错误吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29230657/

相关文章:

gcc - 如何在 Mavericks 上安装 Asterisk?

c++ - 如何将随机整数转换为均匀的实数 [0,1[ 分布

visual-studio - 是否有用于以编程方式运行 Visual Studio 单元测试的 API?

c - gcc 5编译fork()返回父pid 0吗?

c# - 当我在 Visual Studio 中创建 .net core 项目时,我没有获得 TreeView

javascript - 在 Cordova 项目中更改本地主机的端口号

c - undefined reference -- 局部符号

c++ - 为什么 std::cout 以相同的小数精度打印 float 、 double 和长 double ?

C++ - 运算符删除混淆

c++ - 加密文本消息和二进制数据