如何正确编写向量的特征?
How do I write trait for a vector correctly?
我正在尝试练习 traits 和 SFINAE,并尝试为向量编写类似 is_container
的东西:
template <typename... Ts>
struct is_container :std::false_type {};
template <typename... Ts>
struct is_container< std::vector<Ts...> >:std::true_type {};
template < typename T>
inline constexpr auto is_container_v = is_container<T>::value;
居然还有这样一个函数:
template<typename T, typename std::enable_if_t<is_container_v<T>, int > = 0>
auto foo(T&& first, T&& second) {
//do smth...
}
但是这样的调用看不到函数:
std::vector<int> test_vec1(4,0);
std::vector<int> test_vec2(5,3);
foo(test_vec1, test_vec2);
看不出哪里出错了is.I认为vector应该有2个参数:
template<class T, class Alloc>
struct is_container<std::vector<T, Alloc>>
但是可变参数模板不应该起作用吗?还是另一个错误?我很乐意提供帮助
您传递的是 lvalue
而不是 rvalue
,因此要使用您的实现,因为它是使用 std::move()
或更改
auto foo(T&& first, T&& second)
至
auto foo(T& first, T& second)
T&&
是 通用参考 。在本例中,它匹配为 T = std::vector<int>&
。您的 is_container_v<T>
目前 returns
is_container_v<decltype(test_vec1)> // true
is_container_v<std::vector<int>> // true
is_container_v<std::vector<int>&> // false
is_container_v<std::vector<int>&&> // false
为了评估 true
的引用,您需要 在某个点删除引用 使用 std::remove_reference_t
或使用 [=20 更好=]
is_container_v<std::remove_reference_t<std::vector<int>&>> // true
is_container_v<std::remove_reference_t<std::vector<int>&&>> // true
按照你写的方式is_container
其实要包含进去也没那么简单
您可以简单地修改您的函数来处理它
template<typename T, typename std::enable_if_t<is_container_v<std::decay_t<T>>,int>* = nullptr>
auto foo(T&&, T&&) {
return;
}
这既快速又简单,但在这种情况下 is_container
以及 is_container_v
对引用的表现仍然有些出乎意料。 Try it here!
您可以将 is_container_v
别名更改为
template <typename T>
inline constexpr auto is_container_v = is_container<std::decay_t<T>>::value;
虽然 is_container
结构本身仍以意外方式运行,但这并没有解决。
如果你想直接将它包含到 is_container
结构中,你实际上必须以一种或另一种方式重写它,或者通过使其成为 template template class
或做一些事情像这样:
template <typename T1, typename T2 = void>
struct is_container: std::false_type {};
template <typename T>
struct is_container<T,
std::enable_if_t<std::is_same_v<std::decay_t<T>,
typename std::vector<typename std::decay_t<T>::value_type, typename std::decay_t<T>::allocator_type> >>
>: std::true_type {};
我添加了第二个模板参数,默认为 void
。然后可以使用它来启用和禁用 SFINAE 和 std::enable_if_t
的某些专业化。我没有将它设为 template template class
,而是提取值和分配器类型(它们是 std::vector
的模板参数),然后使用 std::decay
确保衰减的数据类型 T
等同于具有元素类型 T::element_type
和分配器 T::allocator_type
的 std::vector
。
Try it here!
我正在尝试练习 traits 和 SFINAE,并尝试为向量编写类似 is_container
的东西:
template <typename... Ts>
struct is_container :std::false_type {};
template <typename... Ts>
struct is_container< std::vector<Ts...> >:std::true_type {};
template < typename T>
inline constexpr auto is_container_v = is_container<T>::value;
居然还有这样一个函数:
template<typename T, typename std::enable_if_t<is_container_v<T>, int > = 0>
auto foo(T&& first, T&& second) {
//do smth...
}
但是这样的调用看不到函数:
std::vector<int> test_vec1(4,0);
std::vector<int> test_vec2(5,3);
foo(test_vec1, test_vec2);
看不出哪里出错了is.I认为vector应该有2个参数:
template<class T, class Alloc>
struct is_container<std::vector<T, Alloc>>
但是可变参数模板不应该起作用吗?还是另一个错误?我很乐意提供帮助
您传递的是 lvalue
而不是 rvalue
,因此要使用您的实现,因为它是使用 std::move()
或更改
auto foo(T&& first, T&& second)
至
auto foo(T& first, T& second)
T&&
是 通用参考 。在本例中,它匹配为 T = std::vector<int>&
。您的 is_container_v<T>
目前 returns
is_container_v<decltype(test_vec1)> // true
is_container_v<std::vector<int>> // true
is_container_v<std::vector<int>&> // false
is_container_v<std::vector<int>&&> // false
为了评估 true
的引用,您需要 在某个点删除引用 使用 std::remove_reference_t
或使用 [=20 更好=]
is_container_v<std::remove_reference_t<std::vector<int>&>> // true
is_container_v<std::remove_reference_t<std::vector<int>&&>> // true
按照你写的方式is_container
其实要包含进去也没那么简单
您可以简单地修改您的函数来处理它
template<typename T, typename std::enable_if_t<is_container_v<std::decay_t<T>>,int>* = nullptr> auto foo(T&&, T&&) { return; }
这既快速又简单,但在这种情况下
is_container
以及is_container_v
对引用的表现仍然有些出乎意料。 Try it here!您可以将
is_container_v
别名更改为template <typename T> inline constexpr auto is_container_v = is_container<std::decay_t<T>>::value;
虽然
is_container
结构本身仍以意外方式运行,但这并没有解决。如果你想直接将它包含到
is_container
结构中,你实际上必须以一种或另一种方式重写它,或者通过使其成为template template class
或做一些事情像这样:template <typename T1, typename T2 = void> struct is_container: std::false_type {}; template <typename T> struct is_container<T, std::enable_if_t<std::is_same_v<std::decay_t<T>, typename std::vector<typename std::decay_t<T>::value_type, typename std::decay_t<T>::allocator_type> >> >: std::true_type {};
我添加了第二个模板参数,默认为
void
。然后可以使用它来启用和禁用 SFINAE 和std::enable_if_t
的某些专业化。我没有将它设为template template class
,而是提取值和分配器类型(它们是std::vector
的模板参数),然后使用std::decay
确保衰减的数据类型T
等同于具有元素类型T::element_type
和分配器T::allocator_type
的std::vector
。 Try it here!