【发布时间】:2018-09-26 05:43:05
【问题描述】:
请考虑第一个 sn-p 代码,其中使用基本 SFINAE 触发器来区分类型是否为随机访问迭代器:
template <typename T, typename = void>
struct is_random_access_iterator : public std::false_type {};
template <typename T>
struct is_random_access_iterator<T,
std::enable_if_t<
std::is_same_v<typename std::iterator_traits<T>::iterator_category, std::random_access_iterator_tag>
>>
: public std::true_type {};
template <typename T>
constexpr bool is_random_access_iterator_v = is_random_access_iterator<T>::value;
此代码按预期编译和工作。现在,考虑第二个 sn-p,我将模板变量替换为 enable_if 条件,根本没有更改其定义:
template <typename T>
constexpr bool has_random_access_iterator_tag =
std::is_same_v<typename std::iterator_traits<T>::iterator_category, std::random_access_iterator_tag>;
template <typename T, typename = void>
struct is_random_access_iterator : public std::false_type {};
template <typename T>
struct is_random_access_iterator<T,
std::enable_if_t<
//std::is_same_v<typename std::iterator_traits<T>::iterator_category, std::random_access_iterator_tag>
has_random_access_iterator_tag<T>
>>
: public std::true_type {};
template <typename T>
constexpr bool is_random_access_iterator_v = is_random_access_iterator<T>::value;
SFINAE 不再工作,编译器(使用 gcc 8 和 clang 7 测试)抱怨 std::iterator_traits 不存在,只要我提供它不是专门用于的类型。
这是一个工作示例:
#include <iostream>
#include <vector>
#include <iterator>
#include <type_traits>
template <typename T>
constexpr bool has_random_access_iterator_tag =
std::is_same_v<typename std::iterator_traits<T>::iterator_category, std::random_access_iterator_tag>;
template <typename T, typename = void>
struct is_random_access_iterator : public std::false_type {};
template <typename T>
struct is_random_access_iterator<T,
std::enable_if_t<
//std::is_same_v<typename std::iterator_traits<T>::iterator_category, std::random_access_iterator_tag>
has_random_access_iterator_tag<T>
>>
: public std::true_type {};
template <typename T>
constexpr bool is_random_access_iterator_v = is_random_access_iterator<T>::value;
int main() {
std::cout << std::boolalpha << "Is random access iterator:\n"
<< "- int: " << is_random_access_iterator_v<int> << '\n'
<< "- int*: " << is_random_access_iterator_v<int*> << '\n'
<< "- v::it: " << is_random_access_iterator_v<std::vector<int>::iterator> << '\n';
}
还有输出:
prog.cc:8:54: 错误:'std::__1::iterator_traits' 中没有名为 'iterator_category' 的类型 std::is_same_v::iterator_category, std::random_access_iterator_tag>; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~
prog.cc:17:9:注意:在此处请求的变量模板特化“has_random_access_iterator_tag”的实例化 has_random_access_iterator_tag ^
prog.cc:22:46: 注意:在类模板部分特化 'is_random_access_iterator >>' [with T = int] 的模板参数推导期间 constexpr bool is_random_access_iterator_v = is_random_access_iterator::value; ^
prog.cc:22:46:注意:在此处请求的模板类“is_random_access_iterator”的实例化中 prog.cc:26:35:注意:在此处请求的变量模板专业化“is_random_access_iterator_v”的实例化中
谁能解释一下为什么?我对此感到沮丧,因为使用模板常量使模板编程更加紧凑和可读性感觉非常自然。
【问题讨论】: