为什么SFINAE在此示例中不能按预期工作?

时间:2016-12-01 06:44:31

标签: c++ sfinae typetraits c++17

#include <iostream>
#include <type_traits>

using namespace std;

template<typename T>
constexpr auto is_pure_input_iterator(int) ->
conditional_t
<
    is_convertible_v
    <
    iterator_traits<T>::iterator_category,
    input_iterator_tag
    >,
    true_type, false_type
>;

template<typename>
constexpr false_type is_pure_input_iterator(...);

int main()
{
    cout << boolalpha 
        << decltype(is_pure_input_iterator<istream_iterator<int>>(0))::value
        << endl;

    return {};
}

预期输出应为:true,但实际值为false

我的代码有什么问题?

1 个答案:

答案 0 :(得分:1)

您错过了typename

缺少typename会使

template<typename T>
constexpr auto is_pure_input_iterator(int) ->
conditional_t
<
  is_convertible_v
  <
    iterator_traits<T>::iterator_category,
    input_iterator_tag
  >,
  true_type, false_type
>;
替换T

失败。默认情况下,iterator_traits<T>::iterator_category被假定为值。对于您的特定T,它是一种类型(对于所有T都是如此)。这似乎被编译器视为替换错误(我不确定您的编译器是否正确 1 )。

替换失败后排除is_pure_input_iterator后,会选择另一个重载,即false_type

typename之前添加iterator_traits<T>::iterator_category可以解决您的问题,因为@ AnT2注意到here

1 由于is_convertible_v需要一个类型作为其第一个参数,并且无论T iterator_traits<T>::iterator_category只能是一个值,您的is_pure_input_iterator可以证明没有T,因此它没有失败。要么检测到这一点并生成诊断(编译器不会发出),您的程序格式不正确,因此不需要诊断。