如何正确编写向量的特征?

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_typestd::vectorTry it here!