geza
geza

Reputation: 29962

What happens with the deduction of a function parameter pack, if it appears in a non-deduced context?

The current draft standard contains this (see the last sentence of this paragraph): "When a function parameter pack appears in a non-deduced context ([temp.deduct.type]), the type of that pack is never deduced."

Now, what does it mean that the pack is never deduced? If the user doesn't specify the value of the pack, and also it is not deduced, shouldn't it be a compile failure?

Current compilers handle this case defining the pack as empty.

This is a stripped down example from the draft:

template<class T1, class ... Types> void g1(Types ..., T1);

void h(int x, float& y) {
  const int z = x;
  g1(x, y, z);                  // error: Types is not deduced
}

This doesn't compile. However, if I modify the example to only use 1 argument, the example compiles:

template<class T1, class ... Types> void g1(Types ..., T1);

void h(int x, float& y) {
  const int z = x;
  g1(x); // compiles
}

Is there anything in the standard that specifies that in this case, the pack should be empty? Why isn't this a compile error?

I understand, that in the latter example, it is obvious that Types is empty, as this is the only way to make the compilation succeed. But, in the previous example, it should also be obvious that the "x, y" part corresponds to Types. I know, that Types is not deduced, so the example shouldn't compile. But then what makes the second example compile? Types is not deduced either here, so if we consider the "error: Types is not deduced" comment (which made the example not compile), this should make the example ill-formed as well.

Shouldn't the cited quote at the beginning sound like: "When a function parameter pack appears in a non-deduced context ([temp.deduct.type]), the pack is deduced as empty." (which is of course looks a little bit weird, because it defines something which is got deduced in a non-deduced context, but isn't this what's happening here?)

Note: there was a similar question before. But I think my question is more explicit, and contains a quote from the current draft (which quote wasn't present back then), so I think it's better to have a new question.


Reflecting to the comment "It is not deduced as empty, it is non deduced and use the one provided by the call (which is empty)"

At first, this seemed to be the answer. However, see this example:

#include <type_traits>

template <typename A, typename ...B, typename C>
void foo(A, B..., C) {
    static_assert(std::is_same_v<A, int>);
    static_assert(sizeof...(B)==0);
    static_assert(std::is_same_v<C, const char *>);
}

int main() {
    foo<int>(42, "");
}

Here, I'd argue whether the call foo provides the value of B or not. If the call had A specified, like foo<int>(42, ""), then I could say this specifies B as empty, because <int> can be considered as <int, empty>. But in the example there are no template arguments specified for foo at all. Sure, the empty template argument list contains the empty set for B. But this way of thinking is a little bit unexpected.

Upvotes: 5

Views: 110

Answers (1)

Shubham Kumar 41
Shubham Kumar 41

Reputation: 1

When a function parameter pack is in a non-deduced context, it means that the compiler cannot determine the types for that pack based on the arguments provided. In this situation, if the pack is not deduced, it does not cause a compilation error; instead, it is treated as an empty pack.

In your first example with g1(x, y, z), the compiler cannot deduce the types for Types because it is in a non-deduced context (due to the presence of T1 after the pack). This results in a compilation error since it requires at least one type to be deduced for Types.

In the second example with g1(x), there are no arguments for Types, so it is clear that Types must be empty. The compiler allows this because it can logically conclude that there are no types to deduce.

The standard does not explicitly state that the pack should be empty in this context, but it is implied that if no types can be deduced, the pack is treated as empty, which allows the code to compile without error. So, while it might seem confusing, the rules of the language allow for this behavior, and it is consistent with how the compiler handles these situations.

Upvotes: -5

Related Questions