C++ 嵌套模板函数的重载
我想了很多关于我的问题的标题,但还是失败了,所以如果你找到一个好的,请编辑它 我正在尝试为C++ 嵌套模板函数的重载,c++,c++11,templates,overloading,language-lawyer,C++,C++11,Templates,Overloading,Language Lawyer,我想了很多关于我的问题的标题,但还是失败了,所以如果你找到一个好的,请编辑它 我正在尝试为向量或其他容器编写一个打印函数,并为容器编写另一个打印函数,因此我想到了以下几点: template<typename T> void print(T const& cont){ for (const auto& i : cont) { cout << i << " "; } cout << endl;
向量
或其他容器
编写一个打印函数,并为容器
编写另一个打印函数,因此我想到了以下几点:
template<typename T>
void print(T const& cont){
for (const auto& i : cont) {
cout << i << " ";
}
cout << endl;
}
template<typename T, template<typename> typename Cont>
void print(Cont<T> const& cont) {
for (const auto& i : cont) {
print(i);
}
}
我的结论是,它仍在尝试调用非嵌套模板打印函数,并在cout
上失败,因为我正在尝试cout一个向量
有人能解释为什么过载解决方案没有像我预期的那样工作,以及我在这里做错了什么吗?即使我将嵌套模板函数重命名为printn,它也会因为不同的原因开始抱怨:
error C2784: 'void prints(const Cont<T> &)': could not deduce template argument for 'const Cont<T> &' from 'std::vector<std::vector<int,std::allocator<int>>,std::allocator<std::vector<int,std::allocator<int>>>>'
错误C2784:'void prints(const Cont&'):无法从'std::vector'推断'const Cont&'的模板参数
简短、简单且不充分的答案是std::vector
有两个模板参数。还应包括一些间距:
template<class T, class A, template<class, class>class C>
void print(C<T,A> const& cont) {
std::cout << "[ ";
bool bFirst = true;
for (const auto& i : cont) {
if (!bFirst)
std::cout << ", ";
bFirst = false;
print(i);
}
std::cout << " ]";
}
这是不够的,因为如果您想要一个更严肃的通用打印机,您确实应该做一些更有趣的事情来检测“this object iterable”和“this object tuple like”。DetectingCont是一种代码,用于检测某些内容是否不可接受(忽略错误的检查答案,阅读我链接的答案)
然后在print
中对(:)
循环执行的参数进行SFINAE测试
接下来要做的事情是检测对象是否类似元组。如果是,您希望打印出元组的每个元素。这将为您提供std::map
和std::unordered_map
支持。请注意,std::array
既像元组,又像iterable
<>这比检测“迭代”有点困难,而且随着C++的标准的扩展,C++的标准也在不断变化,因为C++类的新版本正在扩展。你可以偷懒,只需检测<代码> STD::配对和 >,它将覆盖99%的用例。你也可以使用(或C++概念,如果你生活在未来)来获得你想要的结果,而不必知道你的容器有多少个模板。下面是一个使用尾部返回类型执行SFINAE的示例:
#包括
#包括
模板
自动打印(常量T&cont)->decltype(std::cout您这里的问题是std::vector
有多个模板类型。因此,使用了T重载。发生这种情况的原因是语言中关于如何在模板参数中考虑默认模板参数的歧义。这导致了C中采用的缺陷报告++17和1。要解决此问题,您可以使用可变模板参数并调整基本情况,以便仅打印元素,如
template<typename T>
void print(T const& elem){
cout << elem << " ";
}
template<template<typename...> typename Cont, typename... Params>
void print(Cont<Params...> const& cont) {
for (const auto& i : cont) {
print(i);
}
cout << endl;
}
int main()
{
vector<vector<int>> subsets{{1,2},{3,4}};
print(subsets);
}
1:我必须像我的示例中那样调整基本大小写,因为现在模板temapte版本将调用嵌套向量请包含一个“哦,对不起,我认为缺少了一些东西;”),尽管如此,一个mcve将很好地打印(std::vector{})
使用此技术不起作用。一个简单的解决方案是替换第二个cout@Yakk AdamNevraumont Fair points。我已经更新了我的答案,以依赖begin()
相反。这解决了您的投诉吗?谢谢您的回答@metal,有没有文章或链接让我了解这个decltype是如何工作的?我并没有真正遵循语法。这是旧的std::enable\u if
习惯用法的简化版本。首先要注意的是decltype
返回其参数的类型ER没有实际运行代码-它只是说,“如果我要运行这个代码,会产生什么类型?”然后它偷偷摸摸地使用逗号运算符丢弃第一部分,只是使返回类型总是“代码>空格。如果你考虑这样的声明,它可能会变得更清楚:<代码> StasyAsAsDT(STD::iSySuth.DeCype)。(float{},int{},int>::value)
。它在编译时断言decltype
表达式的类型为int
decltype
正在计算表达式“,”,逗号运算符丢弃最左边的项,只保留最后一项。这清楚了吗?
template<class T, class A, template<class, class>class C>
void print(C<T,A> const& cont) {
std::cout << "[ ";
bool bFirst = true;
for (const auto& i : cont) {
if (!bFirst)
std::cout << ", ";
bFirst = false;
print(i);
}
std::cout << " ]";
}
template<typename T>
void print(T const& i){
std::cout << i;
}
std::vector<int> a={1,2,3};
print(a);
std::cout << "\n";
std::vector<std::vector<int>> b = {a, a, a};
print(b);
std::cout << "\n";
[ 1, 2, 3 ]
[ [ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ] ]
1 2 3 4
5 6 7
8 9
10 20 30
40 50
60
70 80 90
100 110 120
200 400 600
template<typename T>
void print(T const& elem){
cout << elem << " ";
}
template<template<typename...> typename Cont, typename... Params>
void print(Cont<Params...> const& cont) {
for (const auto& i : cont) {
print(i);
}
cout << endl;
}
int main()
{
vector<vector<int>> subsets{{1,2},{3,4}};
print(subsets);
}
1 2
3 4