对于模糊的标题感到抱歉,但我无法想出更好的标题。
我写了一个扁平化容器的函数:
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_type
为int
,std::iterator_traits<OutIt>::value_type>
也为int
。但不知何故,编译器试图实例化第三个模板void flatten<int, OutIt>()
,导致编译器错误(因为我试图迭代一个整数)。
为什么编译器会实例化第3个模板?
答案 0 :(得分:5)
您传递的std::back_insert_iterator
value_type
为void
。因此,if语句的真正分支永远不会被实例化。
一种可能的解决方案是尝试检查分支的功能。这可以使用std::is_assignable
和一些涉及decltype(*declval<OutIt>())
的样板来完成。