什么模式匹配(如果有的话)应用于C++可变参数模板函数调用?

Che*_*Alf 5 c++ templates

我只是天真地写了这个:

#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 ) );
}
Run Code Online (Sandbox Code Playgroud)

它崩溃了Visual C++ 2015更新1,一个ICE(内部编译器错误),并且g ++ 5.1.0维护该函数只接受一个参数,可能是因为忽略了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> _

所以,

  • 为什么以上不能用g ++编译?

  • 如何表达意图(希望从代码中显而易见)?

  • 更一般地说,匹配调用可变参数模板函数的规则是什么?

Col*_*mbo 5

Args出现在非推断的上下文中.在这种情况下,这使得它被推断为空包.

如果要提取最后一个参数但保留通常的演绎规则,可以编写一个简单的帮助器:

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)...);}
Run Code Online (Sandbox Code Playgroud)

演示.

更一般地说,匹配调用可变参数模板函数的规则是什么?

这些都非常冗长,但是没有尾随的函数参数包通常会被推导为空的或产生演绎失败.


在您的特定情况下,尝试index_sequences:

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)...);
}
Run Code Online (Sandbox Code Playgroud)

...并希望编译器能够很好地优化 - Demo 2.或沿着厚颜无耻的道路走下去:

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)...);
}
Run Code Online (Sandbox Code Playgroud)

演示3.