12

According to cppreference, the following code is legal:

lock_guard( MutexTypes&... m, std::adopt_lock_t t );

However, the following code cannot be compiled with clang 3.8 (-std=c++1z):

template<typename... Args>
void f(Args&&..., bool)
{}

int main()
{
    f(1, 2, 3, true); // error! see below for details.
}
1>main.cpp(59,2): error : no matching function for call to 'f'
1>          f(1, 2, 3, true);
1>          ^
1>  main.cpp(54,6) :  note: candidate function not viable: requires 1 argument, but 4 were provided
1>  void f(Args&&..., bool)
1>       ^
1>  1 error generated.

Does C++ allow normal parameters after variadic parameters?

M.M
  • 138,810
  • 21
  • 208
  • 365
xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 1
    My compiler is clang 3.8. gcc 6.2 fails too. – xmllmx Feb 16 '17 at 09:15
  • 4
    Note that with the `lock_guard` example, it's a class constructor, so all the template arguments are known beforehand, rather than trying to deduce them from the function call arguments. – BoBTFish Feb 16 '17 at 09:15
  • It is C++17, not C++11. – ForEveR Feb 16 '17 at 09:28
  • To be precise: variadic parameters is a feature inherited from C and they must be the last ones. You are asking about parameter packs, which were introduced in C++11. – Tadeusz Kopec for Ukraine Feb 16 '17 at 09:30
  • @tad can you please provide a proof or reference for the statement that the C feature is called "variadic parameters"? – Johannes Schaub - litb Feb 16 '17 at 09:40
  • @JohannesSchaub-litb I found this in cppreference: http://en.cppreference.com/w/cpp/language/variadic_arguments "Note: this is different from a function parameter pack expansion, which is indicated by an ellipsis that is a part of a parameter declarator, rather than an ellipsis that appears as a parameter on its own." It is possible that I misunderstood something here or that the sentence is wrong, though. – Tadeusz Kopec for Ukraine Feb 17 '17 at 12:39

1 Answers1

13

The function declaration in your code is valid, however deduction does not work properly for such function templates. Note that the following code is well-formed, and instantiates the specialization void f(int, int, int, bool):

template<typename... Args>
void f(Args&&..., bool) {}

int main() {
    f<int, int, int>(1, 2, 3, true);
}

Note that in C++17, MutexTypes... are the template parameters to the class itself:

template <class... MutexTypes> class lock_guard;

so they are known and do not need to be deduced. Note that the constructor with adopt_lock_t cannot be used for C++17 class template argument deduction since the adopt_lock_t argument occurs after the parameter pack. If the committee had been prescient in C++11, they would have put the adopt_lock_t argument at the beginning rather than at the end, but alas, it is too late now.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312