问题描述
当我尝试在下面使用的类型列表中获取类型的索引时,代码会在使用 else 子句时编译并返回正确的值。但是,当我跳过 else 子句并将 return getIndex<T,Ts...>(x + 1);
放在 if 子句末尾之后,代码无法编译,因为它继续递归展开 getIndex<T,Ts...>
导致如下所示的错误。 gcc
和 clang
就是这种情况。这是预期的吗?
#include <type_traits>
template <typename T,typename U,typename ...Ts>
constexpr int getIndex(int x = 0)
{
if constexpr(std::is_same_v<T,U>)
{
return x;
}
else
{
return getIndex<T,Ts...>(x + 1);
}
}
int main()
{
return getIndex<int,float,double,int,char>();
}
将 return 移到 else 之外时出错
getI.cc: In instantiation of ‘int getIndex(int) [with T = int; U = char; Ts = {}]’:
getI.cc:9:32: recursively required from ‘int getIndex(int) [with T = int; U = double; Ts = {int,char}]’
getI.cc:9:32: required from ‘int getIndex(int) [with T = int; U = float; Ts = {double,char}]’
getI.cc:14:51: required from here
getI.cc:9:32: error: no matching function for call to ‘getIndex<int>(int)’
9 | return getIndex<T,Ts...>(x + 1);
| ~~~~~~~~~~~~~~~~~~^~~~~~~
getI.cc:3:5: note: candidate: ‘template<class T,class U,class ... Ts> int getIndex(int)’
3 | int getIndex(int x = 0)
| ^~~~~~~~
getI.cc:3:5: note: template argument deduction/substitution Failed:
getI.cc:9:32: note: Couldn’t deduce template parameter ‘U’
9 | return getIndex<T,Ts...>(x + 1);
| ~~~~~~~~~~~~~~~~~~^~~~~~~
解决方法
Peter Taran 的回答已经提到了为什么代码用 else
子句编译,但他没有真正提到为什么会出现编译错误或如何修复它。这是您的代码的工作版本:
#include <type_traits>
template <typename T>
constexpr int getIndex(int x = 0)
{
return -1;
}
template <typename T,typename U,typename ...Ts>
constexpr int getIndex(int x = 0)
{
if constexpr (std::is_same_v<T,U>)
{
return x + 1;// NOTE: you have a bug on this line
}
else
{
return getIndex<T,Ts...>(x + 1);
}
}
int main()
{
constexpr int index = getIndex<int,float,double,int,char>();
return 0;
}
诚然,我没有经常使用可变参数模板,但根据我在这里的理解,主要问题在于您的编译错误片段:
getI.cc:9:32: error: no matching function for call to ‘getIndex<int>(int)’
尽管在递归模板中定义了基本情况,但似乎需要可变参数模板才能完全解包。因此,您需要定义一个 getIndex<T>
,即使在您的示例中未达到该代码。添加单个参数 getIndex<T>
允许代码编译和运行。
编辑:This post 也是相关的,很好读,也是您问题的另一种可能解决方案。
,正如我意识到的,损坏的代码是:
template <typename T,typename ...Ts>
constexpr int getIndex(int x = 0)
{
if constexpr(std::is_same_v<T,U>) {
return x;
}
return getIndex<T,Ts...>(x + 1);
}
根据此article:
在 constexpr if 语句中,condition 的值必须是一个 表达式上下文转换为 bool,其中转换是 常量表达式。如果值为真,则 statement-false 为 丢弃(如果存在),否则丢弃 statement-true。
请注意,没有提到丢弃 if-else 子句之外的语句,因此您应该期望递归 getIndex
将被实例化。