c++ - 帮助理解函数和 class 模板之间的区别
c++ - help understanding differences between function and class templates
我正在尝试实现一个 C++ 程序,该程序在给定元素列表的情况下打印出列表中的唯一元素。
我对 C 的了解比对 C++ 的了解要多,但我现在才开始使用 C++ 实际上(编码)。
我只阅读了 C++ 概念什么是模板,我对函数模板很满意,但我刚刚阅读了 class 模板,我想我对在哪里使用感到困惑哪一个,适用于下面的场景。
这是我到目前为止所写的内容(*请注意,函数 isUnique 应该做其他事情,但我现在只在其中编写可验证的操作):
cppArrays.h
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;
template <class T> class cpparray{
private:
int size;
vector<T> elems;
public:
cpparray(int);
~ cpparray();
int isUnique(T arr);
};
template <class T> cpparray<T>::cpparray(int size)
{
vector<T> elems(size);
cout << "Object created with size " << elems.size()<< "\n"<< endl;
}
template <class T> cpparray<T>::~cpparray()
{
cout << "Object del\n" << endl;
}
template <class T> int cpparray<T>::isUnique(T arr)
{
return arr.size();
}
cppArrays.cc
#include "cppArrays.h"
int main()
{
cpparray<int> a(10) ;
//a.push_back(1);
//a.push_back(2);
//cout << a.size() << a.begin() << a.end() << endl;
int b = isUnique(a);
return 0;
}
详情:
[1] 我正在尝试使用模板,因为我希望我的 vector 能够用任何数据类型实例化 - char/float/int.
[2] 我意识到在使用 class 模板时,通过调用
cpparray<int>a(10);
我最终声明了一个 class "cpparray" 的对象 a,其类型为 Integer。这个对吗?
如果是,那么 a.push_back(1)
将不起作用,因为它不引用成员变量而是引用对象本身,因此这是可以理解的我会得到一个编译时错误说 no member named push_back 在 cpparray.
但这让我更难
[1] 了解何时使用 class 模板而不是 function 模板,
[2] 如何在模板 class 中初始化此向量并使用它,给定我的 objective?
您的构造函数应该使用初始化列表来初始化成员,
像这样:
template <class T> array<T>::array(int sz) : size(sz), elems(sz)
{
cout << "Object created with size " << elems.size()<< "\n"<< endl;
}
你所做的是在构造函数中将向量声明为局部向量,将其初始化为大小,局部向量在块结束时被销毁。
当您需要具有编译时变量属性的通用 type 时,请使用 class 模板。模板参数可以是 和 类型的常量,例如
template<typename T, size_t Size>
class MyArray {
T elements_[Size];
public:
MyArray() {}
// ...
};
希望编写可应用于各种应用的通用函数时使用函数模板 types/parameters:
#include <cstdio>
#include <iostream>
template<size_t BufSize, typename... Args>
int strprintf(char(&buf)[BufSize], const char* fmt, Args&&... args)
{
static_assert(BufSize > 0, "Buffer too small");
static_assert(BufSize < (1 << 31), "Buffer too large");
return snprintf(buf, BufSize, fmt, std::forward<Args>(args)...);
}
int main() {
char buf[16];
int printed = strprintf(buf, "hello world %s so long", "oversized load");
std::cout << buf << "\n";
}
以上是一个示例,说明如何替换那些旧的 vsnprintf 转发 printf 类型的函数之一;在编译时完成所有跑腿工作可以大大提高效率。
BufSize
可以被编译器推导出来,因为buf
的类型是char[16]
;它可以通过引用捕获源,类型是 char,数组大小——模板变量——是 16。
也可以有一个模板化的成员函数 class:
template<typename T>
class Foo {
T t_;
public:
Foo() : t_() {}
Foo(const T& t) : t_(t) {}
template<typename RhsT>
bool is_same_size(const RhsT& rhs) {
return t_.size() == rhs.size();
}
};
此示例仅适用于 T 和 RhsT 都具有 size() 成员函数的实例,导致以下结果:
Foo<vector<int>> fvi;
Foo<list<double>> fld;
fvi.is_same_size(fld); // fine
Foo<int> fi;
fvi.is_same_size(fi); // compiler error
我正在尝试实现一个 C++ 程序,该程序在给定元素列表的情况下打印出列表中的唯一元素。
我对 C 的了解比对 C++ 的了解要多,但我现在才开始使用 C++ 实际上(编码)。
我只阅读了 C++ 概念什么是模板,我对函数模板很满意,但我刚刚阅读了 class 模板,我想我对在哪里使用感到困惑哪一个,适用于下面的场景。
这是我到目前为止所写的内容(*请注意,函数 isUnique 应该做其他事情,但我现在只在其中编写可验证的操作):
cppArrays.h
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;
template <class T> class cpparray{
private:
int size;
vector<T> elems;
public:
cpparray(int);
~ cpparray();
int isUnique(T arr);
};
template <class T> cpparray<T>::cpparray(int size)
{
vector<T> elems(size);
cout << "Object created with size " << elems.size()<< "\n"<< endl;
}
template <class T> cpparray<T>::~cpparray()
{
cout << "Object del\n" << endl;
}
template <class T> int cpparray<T>::isUnique(T arr)
{
return arr.size();
}
cppArrays.cc
#include "cppArrays.h"
int main()
{
cpparray<int> a(10) ;
//a.push_back(1);
//a.push_back(2);
//cout << a.size() << a.begin() << a.end() << endl;
int b = isUnique(a);
return 0;
}
详情:
[1] 我正在尝试使用模板,因为我希望我的 vector 能够用任何数据类型实例化 - char/float/int.
[2] 我意识到在使用 class 模板时,通过调用
cpparray<int>a(10);
我最终声明了一个 class "cpparray" 的对象 a,其类型为 Integer。这个对吗?
如果是,那么 a.push_back(1)
将不起作用,因为它不引用成员变量而是引用对象本身,因此这是可以理解的我会得到一个编译时错误说 no member named push_back 在 cpparray.
但这让我更难
[1] 了解何时使用 class 模板而不是 function 模板,
[2] 如何在模板 class 中初始化此向量并使用它,给定我的 objective?
您的构造函数应该使用初始化列表来初始化成员,
像这样:
template <class T> array<T>::array(int sz) : size(sz), elems(sz)
{
cout << "Object created with size " << elems.size()<< "\n"<< endl;
}
你所做的是在构造函数中将向量声明为局部向量,将其初始化为大小,局部向量在块结束时被销毁。
当您需要具有编译时变量属性的通用 type 时,请使用 class 模板。模板参数可以是 和 类型的常量,例如
template<typename T, size_t Size>
class MyArray {
T elements_[Size];
public:
MyArray() {}
// ...
};
希望编写可应用于各种应用的通用函数时使用函数模板 types/parameters:
#include <cstdio>
#include <iostream>
template<size_t BufSize, typename... Args>
int strprintf(char(&buf)[BufSize], const char* fmt, Args&&... args)
{
static_assert(BufSize > 0, "Buffer too small");
static_assert(BufSize < (1 << 31), "Buffer too large");
return snprintf(buf, BufSize, fmt, std::forward<Args>(args)...);
}
int main() {
char buf[16];
int printed = strprintf(buf, "hello world %s so long", "oversized load");
std::cout << buf << "\n";
}
以上是一个示例,说明如何替换那些旧的 vsnprintf 转发 printf 类型的函数之一;在编译时完成所有跑腿工作可以大大提高效率。
BufSize
可以被编译器推导出来,因为buf
的类型是char[16]
;它可以通过引用捕获源,类型是 char,数组大小——模板变量——是 16。
也可以有一个模板化的成员函数 class:
template<typename T>
class Foo {
T t_;
public:
Foo() : t_() {}
Foo(const T& t) : t_(t) {}
template<typename RhsT>
bool is_same_size(const RhsT& rhs) {
return t_.size() == rhs.size();
}
};
此示例仅适用于 T 和 RhsT 都具有 size() 成员函数的实例,导致以下结果:
Foo<vector<int>> fvi;
Foo<list<double>> fld;
fvi.is_same_size(fld); // fine
Foo<int> fi;
fvi.is_same_size(fi); // compiler error