c++ 为什么我需要constexpr在递归与参数包[重复]

kcrjzv8t  于 2023-11-19  发布在  其他
关注(0)|答案(2)|浏览(90)

此问题在此处已有答案

if constexpr vs if in light of compiler optimization and code performance(2个答案)
2天前关闭。
我有一个简单的递归函数来打印参数包中的每个参数

#include <iostream>

template<typename T, typename... Args>
void printArgs(T first, Args... rest) {
    std::cout << first << " ";
    
    if constexpr (sizeof...(rest) > 0) { // doesn't compile without constexpr
        printArgs(rest...);
    } else {
        return;
    }
}

int main() {
    printArgs(1, 2, "hello");

    return 0;
}

字符串

**Q1:**为什么if中需要constexpr才能编译程序?
**Q2:**条件不应该是sizeof...(rest) > 1吗?因为如果size是1,我再调用printArgs,那么rest不就为空了吗?(可以为空吗?)

我看到过类似的问题,比如"constexpr if" vs "if" with optimizations - why is "constexpr" needed?,但我看不出这些答案与我的情况有什么关系。

mnemlml8

mnemlml81#

我将从第二个Q开始,因为这个问题的答案也解释了Q1。
Q2:条件不应该是sizeof...(rest) > 1吗?因为如果大小是1,我再次调用printArgs,那么rest不是空的吗?(它是空的吗?)
你的错误是把sizeof...(rest)的个数记为T。但是如果你调用printArgs(onlyOne),那么T是从onlyOne推导出来的,Args是空的,而sizeof...(rest)0。你的函数可以用1(T first)加上零或更多(Args... rest)参数来调用。
Q1:为什么我需要constexpr在if中的程序编译?
如果删除constexpr,则会得到以下error

<source>: In instantiation of 'void printArgs(T, Args ...) [with T = const char*; Args = {}]':
<source>:8:18:   recursively required from 'void printArgs(T, Args ...) [with T = int; Args = {const char*}]'
<source>:8:18:   required from 'void printArgs(T, Args ...) [with T = int; Args = {int, const char*}]'
<source>:15:14:   required from here
<source>:8:18: error: no matching function for call to 'printArgs()'
    8 |         printArgs(rest...);
      |         ~~~~~~~~~^~~~~~~~~
<source>:4:6: note: candidate: 'template<class T, class ... Args> void printArgs(T, Args ...)'
    4 | void printArgs(T first, Args... rest) {
      |      ^~~~~~~~~
<source>:4:6: note:   template argument deduction/substitution failed:
<source>:8:18: note:   candidate expects at least 1 argument, 0 provided
    8 |         printArgs(rest...);
      |         ~~~~~~~~~^~~~~~~~~

字符串
因为在最后一次递归中,只有1个参数传递给printArgs,而rest没有元素。在这种情况下,printArgs(rest...)无法编译,因为(见上文)你的函数只能用1个或更多个参数调用。if constexpr导致false分支被丢弃,调用printArgs()的部分永远不会示例化。

6mzjoqzu

6mzjoqzu2#

你也不必使用显式递归,从C++17开始,你可以使用折叠表达式。
下面的代码将输出1, 2, hello

#include <iostream>

template<typename First, typename... Args>
void printArgs(First&& first, Args&&... rest) 
{
    std::cout << std::forward<First>(first);

    //https://en.cppreference.com/w/cpp/language/fold
    // the part before ,... will be repeated/expanded
    // each time with one argument
    ((std::cout << ", " << std::forward<Args>(rest)),...);
}

int main() 
{
    printArgs(1, 2, "hello");

    return 0;
}

字符串

相关问题