无法编译包含"if constexpr"的函数模板实例化

cannot compile function template instantiation containing "if constexpr"

本文关键字:函数模板 实例化 constexpr if 编译 包含      更新时间:2023-10-16

很抱歉标题含糊不清,但我想不出更好的标题。

我写了一个函数来展平容器:

template <typename Container, typename OutIt>
void flatten(const Container& container, OutIt res)
{
if constexpr (std::is_convertible_v<typename Container::value_type, typename std::iterator_traits<OutIt>::value_type>)
{
for (const auto& value : container)
{
*res = value;
++res;
}
}
else
{
for (const auto& subContainer : container)
flatten(subContainer, res);
}
}

我希望它像这样使用:

vector<vector<int>> test = {{1}, {2, 3, 4}, {5, 6}, {7}};
vector<int> res;
flatten(test, std::back_inserter(res));

这基本上应该将所有嵌套值从test复制到res,以便res == { 1, 2, 3, 4, 5, 6, 7 }

但是,如果我想编译代码,编译器会抛出一些错误,这些错误基本上是说,else分支中的代码被编译而不是if constexpr块。

即第一个实例化是void flatten<vector<vector<int>>, OutIt>()这是正确的。第二个实例化(由else块触发)是void flatten<vector<int>, OutIt>()这也是正确的。但是对于第二个实例,if constexpr表达式的计算结果应该为true,因为vector<int>::value_typeint的,std::iterator_traits<OutIt>::value_type>也是int的。但不知何故,编译器尝试实例化第三个模板void flatten<int, OutIt>()这会导致编译器错误(因为我尝试迭代整数)。

为什么编译器要实例化第三个模板?

你传入一个std::back_insert_iteratorvalue_typevoid。因此,if 语句的真正分支永远不会实例化。

一个可能的解决方案是尝试检查分支的功能。这可以通过std::is_assignable和一些涉及decltype(*declval<OutIt>())的样板来完成。