SFINAE问题在创建" is_iterable"特质 - 这是一个gcc bug吗?

时间:2015-03-24 10:51:32

标签: 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 *(以及旧版本)并在VS2012中成功并成功。我的断言是,可变参数版本总是在重载决策中排在最后(因此不应该有歧义),所以谁在这里?

是否存在跨平台解决方案/替代方案?

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

3 个答案:

答案 0 :(得分:3)

只有当函数的实际参数与省略号转换更好匹配时才有效。请记住,没有参数的默认值参数不参与重载决策。

解决方案是添加另一个参数并传递一个参数:

template<class T> static true_type  is_beg_iterable(int,   // <- for disambiguation
    typename T::const_iterator = C().begin());

template<class T> static false_type is_beg_iterable(...); 

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

Live example.

答案 1 :(得分:2)

从C ++ 17开始,定义Creating default object from empty value. 特征的惯用方式是:

is_iterable

Live demo

答案 2 :(得分:1)

以下作品(至少使用gcc 4.9.2):

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

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

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

Live example