What pattern matching (if any) is used to call the C ++ template template function?

I just naively wrote this:

#include <stdio.h> template< class... Args > auto format_for( Args... args, int last_arg ) -> char const* { // using Specifier = char const [3]; // static Specifier const s[] = { {'%', 'f'+(0*args), ' '}..., {'%', 'f', 0} }; return reinterpret_cast<char const*>( "" ); } auto main() -> int { printf( "'%s'\n", format_for( 5, 2, 1 ) ); } 

It discards the Visual C ++ 2015 1 update, ICE (internal compiler error), and g ++ 5.1.0 claims that the function accepts only one argument, presumably as a result of ignoring Args after the template parameter does not Args :

  C: \ my \ forums \ so \ 081> cl printf.cpp / Feb
 printf.cpp
 printf.cpp (14): fatal error C1001: An internal error has occurred in the compiler.
 (compiler file 'f: \ dd \ vctools \ compiler \ cxxfe \ sl \ p1 \ cxx \ dymto.c', line 6771)
  To work around this problem, try simplifying or changing the program near the locations listed above.
 Please choose the Technical Support command on the Visual C ++
  Help menu, or open the Technical Support help file for more information

 C: \ my \ forums \ so \ 081> g ++ printf.cpp
 printf.cpp: In function 'int main ()':
 printf.cpp: 14: 43: error: no matching function for call to 'format_for (int, int, int)'
      printf ("'% s' \ n", format_for (5, 2, 1));
                                            ^
 printf.cpp: 4: 6: note: candidate: template <class ... Args> const char * format_for (Args ..., int)
  auto format_for (Args ... args, int last_arg)
       ^
 printf.cpp: 4: 6: note: template argument deduction / substitution failed:
 printf.cpp: 14:43: note: candidate expects 1 argument, 3 provided
      printf ("'% s' \ n", format_for (5, 2, 1));
                                            ^

 C: \ my \ forums \ so \ 081> _

So,

  • Why is the above not compiling with g ++?

  • How can one express an intention (I hope it is obvious from the code)?

  • In general, what are the rules for matching a call with a function declaration for a variational pattern?

+5
source share
1 answer

Args appears in a non-printable context. In this case, it is output as an empty packet .

If you want to extract the last argument, but support the usual rules of deduction, you can write a simple helper:

 template <typename U> constexpr U&& last(U&& u) {return std::forward<U>(u);} template <typename U, typename... T> constexpr decltype(auto) last(U&&, T&&... t) {return last(std::forward<T>(t)...);} 

Demo

More generally, what are the rules for matching a call to declaring a function of a variational pattern?

These are quite detailed, but packages of parameter parameters that are not finite, as a rule, are either empty or cause a failure.


In your specific case, try index_sequence s:

 template <class... Args, std::size_t... indices> auto format_for( std::index_sequence<indices...>, Args... args ) { auto tup = std::forward_as_tuple(std::forward<Args>(args)...); using Specifier = char const [3]; static Specifier const s[] = { {'%', (char)('f'+(0*std::get<indices>(tup))), ' '}..., {'%', 'f', 0} }; int last_arg = std::get<sizeof...(Args)-1>(tup); return s; } template <class... Args> auto format_for( Args&&... args ) { return format_for(std::make_index_sequence<sizeof...(Args)-1>{}, std::forward<Args>(args)...); } 

... and hope the compiler optimizes well - Demo 2 . Or go down the sassy road:

 template <class... Args, std::size_t... indices> auto format_for( std::index_sequence<indices...>, Args... args ) { using Specifier = char const [3]; static Specifier const s[] = { {'%', (char)(indices == sizeof...(Args)-1? 'f' : 'f'+(0*args)), ' '}... }; int last_arg = last(args...); // As before return s; } template <class... Args> auto format_for( Args&&... args ) { return format_for(std::make_index_sequence<sizeof...(Args)>{}, std::forward<Args>(args)...); } 

Demo 3 .

+5
source

Source: https://habr.com/ru/post/1241746/


All Articles