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

What pattern matching (if any) is applied for C++ variadic template function invocation?

本文关键字:模式匹配 什么 如果 应用 变参 参数 函数调用 C++      更新时间:2023-10-16

我只是天真地写了这个:

#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 ) );
}

它使Visual C++ 2015 update 1崩溃,ICE(内部编译器错误),并且g ++ 5.1.0认为该函数仅接受一个参数,可能是由于无法匹配此模板参数后忽略Args

C:\my\forums\so\081> cl printf.cpp/Feb打印f.cppprintf.cpp(14): 致命错误 C1001: 编译器中发生内部错误。(编译器文件 'F:\DD\VCtools\Compiler\cxxfe\SL\P1\cxx\DyMto.c',第 6771 行) 要变通解决此问题,请尝试简化或更改上面列出的位置附近的程序。请在可视C++上选择技术支持命令 "帮助"菜单,或打开技术支持帮助文件以获取更多信息C:\my\forums\so\081> g++ printf.cppprintf.cpp: 在函数 'int main()' 中:printf.cpp:14:43:错误:调用"format_for(int, int, int)"没有匹配函数     printf( "'%s'", format_for( 5, 2, 1 ) );                                           ^printf.cpp:4:6:注意:候选人:模板<类...Args> const char* format_for(Args ..., int) auto format_for( args... args, int last_arg )      ^printf.cpp:4:6:注意:模板参数推导/替换失败:printf.cpp:14:43:注意:候选人期望 1 个参数,提供 3 个参数     printf( "'%s'", format_for( 5, 2, 1 ) );                                           ^C:\my\forums\so\081> _

所以

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

  • 如何表达意图(希望从代码中可以明显看出)?

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

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)...);}

演示。

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

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


在您的特定情况下,请尝试index_sequence

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)...);
}

。并希望编译器优化良好 - 演示 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)...);
}

演示 3.