我想写一个sort
函数,它接受包含多个容器的可变参数:void sort(C &c, Rest&... rest)
;
template<typename T>
struct is_list{
static constexpr bool value = false;
};
template<typename T>
struct is_list<std::list<T>>{
static constexpr bool value = true;
};
template<typename T>
struct is_list<std::forward_list<T>>{
static constexpr bool value = true;
};
template<typename C, typename...Rest>
void sort(C &c, Rest&... rest){
if(is_list<C>::value == true) c.sort();
else std::sort(c.begin(), c.end());
sort(rest...);
}
//main file
std::vector<int> vec{1, 2, 3};
sort(vec);
两个错误:
if(is_list<C>::value == true) c.sort();
但逻辑上if语句不应该执行,因为我传递了一个向量而不是列表。
sort(rest...);
第二个错误很明显,但错误1的原因是什么。
我通过
解决了这个问题template<typename T>
struct is_list{
static constexpr bool value = false;
};
template<typename T>
struct is_list<std::list<T>>{
static constexpr bool value = true;
};
template<typename T>
struct is_list<std::forward_list<T>>{
static constexpr bool value = true;
};
template<typename C, typename std::enable_if<!is_list<C>::value>::type* = nullptr>
void sort(C &c){
sort(c.begin(), c.end());
}
template<typename C, typename std::enable_if<is_list<C>::value>::type* = nullptr>
void sort(C &c){
c.sort();
}
template<typename C, typename...Rest>
void sort(C &c, Rest&... rest){
sort(c);
sort(rest...);
}
答案 0 :(得分:3)
第一个错误来自于编译器实例化模板时,它编译整个函数,而不仅仅是满足条件的if
分支。
这意味着当您将向量传递给sort
时,它会以C
实例化为std::vector
,但之后会尝试编译(nb:not执行),c.sort()
无论如何。在这种情况下,std::vector
没有sort()
成员。这就是您收到此错误的原因。因为编译器会尝试实例化整个模板(即用实际类型替换C
并编译每一行)。
要修复它,您需要重新设计模板,以便实例化为您的类型完全编译的版本。 std::enable_if
可能是一个潜在的解决方案:
template<typename C, typename std::enable_if<is_list<C>::value>::type >
void sort(C &c){
c.sort();
}
template<typename C, typename std::enable_if<!is_list<C>::value>::type* = nullptr>
void sort(C &c){
std::sort(c.begin(), c.end());
}
答案 1 :(得分:1)
一旦你看到了你的代码,你的代码就会遇到另一个问题 你没有处理递归的终端案例 我还添加了完美转发
如果您使用的是c ++ 17,则可以使用constexpr(如果
)template<typename C, typename...Rest>
void sort(C &c, Rest&& ... rest){
if constexpr (is_list<C>::value == true) c.sort();
else std::sort(c.begin(), c.end());
if constexpr (sizeof...(rest) >= 1) // empty case
sort(std::forward<Rest>(rest)...);
}
否则你可以使用模板专业化,重载甚至SFINEA 但我认为重载是c ++ 11最简单的方法
//handleing empty case for terminal recursion
void sort() {}
//list case
template<typename T, typename...Rest>
void sort(std::list<T>& c, Rest&& ... rest){
c.sort();
sort(std::forward<Rest>(rest)...);
}
//forward list case
template<typename T, typename...Rest>
void sort(std::forward_list<T>& c, Rest&& ... rest){
c.sort();
sort(std::forward<Rest>(rest)...);
}
//other containers case
template<typename C, typename...Rest>
void sort(C&& c, Rest&& ... rest) {
std::sort(c.begin(), c.end());
sort(std::forward<Rest>(rest)...);
}