Вопрос

Trying to search for this answer, I noticed that the titles of the questions on variadic template functions are very uninformative when searching on SO. You only known that the question is about variadic template. Hopefully my question wasn't asked before and the title will help people finding it.

So, I want to make a function which has a variadic template parameter. More precisely, as an example, let say I want to have a compile time permutation of an array. Here is a working code:

template <typename... Ts> struct Sequence {};

template <typename T, unsigned Size, typename... SeqTis> struct Permute;

template <typename T, unsigned Size, typename... SeqTis>
struct Permute<T, Size, Sequence<SeqTis...> > {
  using type = typename std::array<T, Size>;
  constexpr static type permute(const type ar) {
    return { (ar[SeqTis::value])... };
  }
};

Then the following is perfectly legal:

using T0 = std::integral_constant<int, 0>;
using T1 = std::integral_constant<int, 1>;
using T2 = std::integral_constant<int, 2>;
using Perm120 = Permute<int, 3, Sequence<T1, T2, T0> >;
using arr3 = Perm120::type;
constexpr arr3 ar {5,7,2};
constexpr arr3 arPerm = Perm120::permute(ar);

I'm now trying to avoid using a structure so I wrote the following:

template <typename T, unsigned Size, typename... SeqTis>
constexpr typename std::array<T, Size>
permutefun<T, Size, Sequence<SeqTis...> >(const typename std::array<T, Size> ar) {
  return { (ar[SeqTis::value])... };
}

And GCC refuse it saying that

essai.cpp:19:11: error: expected initializer before ‘<’ token
  permutefun<T, Size, Sequence<SeqTis...> >(const typename std::array<T, Size> ar) {
           ^

Why is it so ?

Это было полезно?

Решение

To add to previous answers, you also need to have a convenient syntax for calling permutefun, but the current template parameters

template <typename T, unsigned Size, typename... SeqTis>

are not convenient because you'd have to call

permutefun <int, 3, T1, T2, T0>(ar);

A solution is to deduce arguments in two steps:

#include <array>

template <typename... Ts> struct Sequence {};

template <typename... SeqTis, typename T, unsigned long Size>
constexpr std::array<T, Size>
permutefun(Sequence<SeqTis...>, const std::array<T, Size> ar) {
  return { (ar[SeqTis::value])... };
}

template <typename Seq, typename T, unsigned long Size>
constexpr std::array<T, Size>
permutefun(const std::array<T, Size> ar) {
  return permutefun(Seq(), ar);
}

int main ()
{
    using T0 = std::integral_constant<int, 0>;
    using T1 = std::integral_constant<int, 1>;
    using T2 = std::integral_constant<int, 2>;

    using Perm120 = Sequence<T1, T2, T0>;
    using arr3 = std::array <int, 3>;
    constexpr arr3 ar = {5,7,2};
    constexpr arr3 arPerm = permutefun <Perm120>(ar);
}

Now arguments T, Size appear last so are automatically deduced by the input array. Argument Seq comes first, but to deduce its "unpacked" parameters SeqTis... you need a call to a second overload of permutefun. This allows the convenient syntax

permutefun <Perm120>(ar);

The 2nd overload may be useful by itself, because it allows the alternative syntax

Perm120 perm;
permutefun(perm, ar);

Also note that std::array::operator[] is constexpr only in C++14. For instance, this does not compile with Clang 3.3 and -std=c++11.

Другие советы

Your syntax looks like an attempt at a partial function specialisation, but that's not what you want, so that's not what you should write. Since partial function specialisations aren't supported, the compiler gets confused by the unexpected <.

template <typename T, unsigned Size, typename... SeqTis>
constexpr std::array<T, Size>
permutefun(const std::array<T, Size> ar) {
//        ^ removed the <...>
  return { (ar[SeqTis::value])... };
}

Also, you don't need typename here, as std::array<T, Size> is already known to be a type. It's fine to leave it in, but it works just as well without it.

Do you mean:

template <typename T, unsigned Size, typename... SeqTis>
constexpr std::array<T, Size>
permutefun(const typename std::array<T, Size> ar) {
    return { (ar[SeqTis::value])... };
}

partial template specialization is not possible for function.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top