Home > Mobile >  How to pass a std::array to a function template which can accept std::vector
How to pass a std::array to a function template which can accept std::vector

Time:11-17

I'm trying to write a template, which can accept some sequence containers:

template <typename S,
          typename = std::enable_if_t<
              std::is_same<S, std::array<typename S::value_type>, S::size()>::value ||
              std::is_same<S, std::vector<typename S::value_type>>::value>>
std::string arr2String(const S& seqContainer) {
    std::stringstream res;
    for (const auto& element : seqContainer) {
        res << element << "|";
    }
    return res.str();
}

However, this can't be compiled because of S::size(). Obviously, there is no such a thing.

Is it possible to make such a template function, which can handle std::vector and std::array?

CodePudding user response:

If you want to restrict your template to work for only std::array or std::vector, you can write some helper traits

template <typename>
struct is_array : std::false_type {}

template <typename T, std::size_t N>
struct is_array<std::array<T, N>> : std::true_type {}

template <typename>
struct is_vector : std::false_type {}

template <typename... Ts>
struct is_vector<std::vector<Ts...>> : std::true_type {}

template <typename S,
          typename = std::enable_if_t<
              is_array<S>::value ||
              is_vector<S>::value>>
std::string arr2String(const S& seqContainer) {
    std::stringstream res;
    for (const auto& element : seqContainer) {
        res << element << "|";
    }
    return res.str();
}

Otherwise you can SFINAE on something more general

template <typename S, typename = typename S::value_type>
std::string arr2String(const S& seqContainer) {
    std::stringstream res;
    for (const auto& element : seqContainer) {
        res << element << "|";
    }
    return res.str();
}

CodePudding user response:

Your code could in fact be compiled if you instantiated an array and took its size, which is constexpr.

template <typename S,
        typename = std::enable_if_t<
            std::is_same<S, std::array<typename S::value_type, S{}.size()>>::value ||
            std::is_same<S, std::vector<typename S::value_type>>::value>>
std::string arr2String(const S& seqContainer) {
    std::stringstream res;
    for (const auto& element : seqContainer) {
        res << element << "|";
    }
    return res.str();
}

This of course would be problematic if default initialization of your value type is expensive.

  • Related