可以检测 std::vector 的 C++ 模板化 class 函数
C++ Templated class function that can detect std::vector
如果我有模板 class,我可以执行以下操作来检测是否传递了矢量:
template<typename T> struct is_vector { static const bool value=false; };
template<typename T> struct is_vector<std::vector<T>> { static const bool value=true; };
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if (is_vector<T>::value) {
std::cout << "vector\n";
//obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
int main() {
Parser<int> p1;
p1.parse(123);
Parser<std::vector<int>> p2;
p2.parse({ 1, 2, 3});
return 0;
}
输出:
not vector
vector
我可以检测到向量,但是当我取消注释 push_back
调用时编译器会报错:
main.cpp: In instantiation of ‘void Parser<T>::parse(T) [with T = int]’:
main.cpp:26:14: required from here
main.cpp:15:17: error: request for member ‘push_back’ in ‘obj’, which is of non-class type ‘int’
obj.push_back(T {});
~~~~^~~~~~~~~
显然,int 没有 push_back
函数,但 vector 有。 is_vector
调用在运行时求值,但 push_back
在编译时被捕获。
通过部分模板专业化,我可以做我想做的事:
template<typename T>
void parse(T obj) {
std::cout << "not vector: " << obj << "\n";
}
template<typename T>
void parse(std::vector<T> obj) {
std::cout << "is vector\n";
for (auto i : obj) std::cout << i << " ";
obj.push_back(T {});
std::cout << "\n";
for (auto i : obj) std::cout << i << " ";
std::cout << "\n";
}
int main() {
parse(1);
parse('a');
parse(std::vector<int> { 1, 2, 3 });
return 0;
}
输出:
not vector: 1
not vector: a
is vector
1 2 3
1 2 3 0
那么,如何在编译时或运行时结合这两个想法?也就是说,有一个模板化的 class 和一个可以处理向量和非向量的函数?
您正在寻找的是 C++17 中的一项新功能,if constexpr
。它与常规 if
相同,只是条件是在编译时评估的,并且在实例化分支时将在编译时丢弃未采用的分支。丢弃的分支不需要格式正确。因此,对于您的示例:
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if constexpr (is_vector<T>::value) {
std::cout << "vector\n";
obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
请参阅 for some more talk on the differences. You can also read the cppreference page on if statements 以详细了解一些基本细节。
如果我有模板 class,我可以执行以下操作来检测是否传递了矢量:
template<typename T> struct is_vector { static const bool value=false; };
template<typename T> struct is_vector<std::vector<T>> { static const bool value=true; };
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if (is_vector<T>::value) {
std::cout << "vector\n";
//obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
int main() {
Parser<int> p1;
p1.parse(123);
Parser<std::vector<int>> p2;
p2.parse({ 1, 2, 3});
return 0;
}
输出:
not vector
vector
我可以检测到向量,但是当我取消注释 push_back
调用时编译器会报错:
main.cpp: In instantiation of ‘void Parser<T>::parse(T) [with T = int]’:
main.cpp:26:14: required from here
main.cpp:15:17: error: request for member ‘push_back’ in ‘obj’, which is of non-class type ‘int’
obj.push_back(T {});
~~~~^~~~~~~~~
显然,int 没有 push_back
函数,但 vector 有。 is_vector
调用在运行时求值,但 push_back
在编译时被捕获。
通过部分模板专业化,我可以做我想做的事:
template<typename T>
void parse(T obj) {
std::cout << "not vector: " << obj << "\n";
}
template<typename T>
void parse(std::vector<T> obj) {
std::cout << "is vector\n";
for (auto i : obj) std::cout << i << " ";
obj.push_back(T {});
std::cout << "\n";
for (auto i : obj) std::cout << i << " ";
std::cout << "\n";
}
int main() {
parse(1);
parse('a');
parse(std::vector<int> { 1, 2, 3 });
return 0;
}
输出:
not vector: 1
not vector: a
is vector
1 2 3
1 2 3 0
那么,如何在编译时或运行时结合这两个想法?也就是说,有一个模板化的 class 和一个可以处理向量和非向量的函数?
您正在寻找的是 C++17 中的一项新功能,if constexpr
。它与常规 if
相同,只是条件是在编译时评估的,并且在实例化分支时将在编译时丢弃未采用的分支。丢弃的分支不需要格式正确。因此,对于您的示例:
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if constexpr (is_vector<T>::value) {
std::cout << "vector\n";
obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
请参阅