以下是一个类的示例,它循环访问 STL 容器并打印出每个元素,并附有 main() 的初始化代码。
似乎编译器在编译时解析了整个 ContainerPrinterClass,并在它到达传入的 STL 容器之一中的元素不支持的行时抛出错误,例如 element.first/element.second
对于类型 int
在 vector 中。然而,它甚至不应该进入那种状态,因为流量控制明确规定只能进入它 if (std::is_same<T, std::map<int, std::string>>::value)
是真的。
本地图被传递到打印函数并且编译器在 else
中标记错误时,情况正好相反。它尝试打印元素的条件,这是一个 std::pair 但不能。但它甚至不应该处于 else 状态,因为如果传递给它一个映射,执行将转到 if
。条件并跳过 else
完全。
我也尝试用 (typeid(*container) == typeid(std::map<int, std::string>))
代替和 dynamic_cast
检查元素是否为 std::pair
结果相同,编译器在编译时解析打印机函数中的所有条件(甚至是特定类型的不正确条件)。
那么有没有人知道如何提供类似于 Java 的 instanceOf
的这种模板/通用功能?并且不让编译器在它不应该进入该特定类型的条件下盲目地解析代码?
// the printer class
class ContainterPrinterClass {
public:
ContainterPrinterClass() {};
template<class T> void printElementsInContainer(T *container) {
// if container type is map, print key and value
if (std::is_same<T, std::map<int, std::string>>::value) {
for each (auto element in *container) {
std::cout << "key: " << element.first << " val: " << element.second << std::endl;
}
} else {
// else if container is a vector, print just element
for each (auto element in *container) {
std::cout << "val: " << element << std::endl;
}
}
}
};
// in main()
ContainterPrinterClass containerPrinterClass;
std::vector<int> vectorOfInts = {1};
containerPrinterClass.printElementsInContainer<std::vector<int>>(&vectorOfInts);
std::map<int, std::string> mapOfStrings = {std::pair<int, std::string>(2, "Two")};
containerPrinterClass.printElementsInContainer<std::map<int, std::string>>(&mapOfStrings);
但是它不会编译并给出以下错误:
1>e:\workbench\projects\visualstudio_workspaces\tuts\testbed1\basic_app\basic_app.cpp(503): error C2228: left of '.first' must have class/struct/union
1> type is 'int'
1> e:\workbench\projects\visualstudio_workspaces\tuts\testbed1\basic_app\basic_app.cpp(747) : see reference to function template instantiation 'void ContainterPrinterClass::printElementsInContainer<std::vector<int,std::allocator<_Ty>>>(T *)' being compiled
1> with
1> [
1> _Ty=int
1> , T=std::vector<int,std::allocator<int>>
1> ]
1>e:\workbench\projects\visualstudio_workspaces\tuts\testbed1\basic_app\basic_app.cpp(503): error C2228: left of '.second' must have class/struct/union
1> type is 'int'
1>e:\workbench\projects\visualstudio_workspaces\tuts\testbed1\basic_app\basic_app.cpp(508): error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::pair<const _Kty,_Ty>' (or there is no acceptable conversion)
1> with
1> [
1> _Kty=int
1> , _Ty=std::string
1> ]
1> c:\visualstudio2013pro\vc\include\ostream(498): could be 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_streambuf<char,std::char_traits<char>> *)'
1> c:\visualstudio2013pro\vc\include\ostream(478): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(const void *)'
1> c:\visualstudio2013pro\vc\include\ostream(458): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(long double)'
1> c:\visualstudio2013pro\vc\include\ostream(438): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(double)'
1> c:\visualstudio2013pro\vc\include\ostream(418): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(float)'
1> c:\visualstudio2013pro\vc\include\ostream(397): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned __int64)'
1> c:\visualstudio2013pro\vc\include\ostream(377): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(__int64)'
1> c:\visualstudio2013pro\vc\include\ostream(356): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned long)'
1> c:\visualstudio2013pro\vc\include\ostream(336): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(long)'
1> c:\visualstudio2013pro\vc\include\ostream(316): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned int)'
1> c:\visualstudio2013pro\vc\include\ostream(291): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(int)'
1> c:\visualstudio2013pro\vc\include\ostream(271): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned short)'
1> c:\visualstudio2013pro\vc\include\ostream(237): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(short)'
1> c:\visualstudio2013pro\vc\include\ostream(217): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::_Bool)'
1> c:\visualstudio2013pro\vc\include\ostream(210): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::ios_base &(__cdecl *)(std::ios_base &))'
1> c:\visualstudio2013pro\vc\include\ostream(203): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_ios<char,std::char_traits<char>> &(__cdecl *)(std::basic_ios<char,std::char_traits<char>> &))'
1> c:\visualstudio2013pro\vc\include\ostream(197): or 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_ostream<char,std::char_traits<char>> &(__cdecl *)(std::basic_ostream<char,std::char_traits<char>> &))'
1> c:\visualstudio2013pro\vc\include\ostream(699): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)'
1> c:\visualstudio2013pro\vc\include\ostream(746): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
1> c:\visualstudio2013pro\vc\include\ostream(784): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)'
1> c:\visualstudio2013pro\vc\include\ostream(831): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
1> c:\visualstudio2013pro\vc\include\ostream(957): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const signed char *)'
1> c:\visualstudio2013pro\vc\include\ostream(964): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,signed char)'
1> c:\visualstudio2013pro\vc\include\ostream(971): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const unsigned char *)'
1> c:\visualstudio2013pro\vc\include\ostream(978): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,unsigned char)'
1> c:\visualstudio2013pro\vc\include\ostream(988): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>,std::pair<const _Kty,_Ty>>(std::basic_ostream<char,std::char_traits<char>> &&,const std::pair<const _Kty,_Ty> &)'
1> with
1> [
1> _Kty=int
1> , _Ty=std::string
1> ]
1> c:\visualstudio2013pro\vc\include\ostream(1026): or 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const std::error_code &)'
1> while trying to match the argument list '(std::basic_ostream<char,std::char_traits<char>>, std::pair<const _Kty,_Ty>)'
1> with
1> [
1> _Kty=int
1> , _Ty=std::string
1> ]
1> e:\workbench\projects\visualstudio_workspaces\tuts\testbed1\basic_app\basic_app.cpp(750) : see reference to function template instantiation 'void ContainterPrinterClass::printElementsInContainer<std::map<int,std::string,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>>(T *)' being compiled
1> with
1> [
1> _Kty=int
1> , _Ty=std::string
1> , T=std::map<int,std::string,std::less<int>,std::allocator<std::pair<const int,std::string>>>
1> ]
最佳答案
当函数模板被实例化时,它的所有代码都需要是正确的代码。当您想要执行依赖于模板参数功能的代码时,您需要利用相关功能分派(dispatch)到合适的函数模板。例如,您可以这样重写代码:
template<class T>
typename std::enable_if<std::is_same<T, std::map<int, std::string>>::value>::type
printElementsInContainer(T *container) {
for (auto&& element: *container) {
std::cout << "key: " << element.first << " val: " << element.second << '\n';
}
}
template<class T>
typename std::enable_if<!std::is_same<T, std::map<int, std::string>>::value>::type
printElementsInContainer(T *container) {
for (auto&& element: *container) {
std::cout << "val: " << element << '\n';
}
}
在某种程度上,使用 std::enable_if<...>
做相应的类型条件。
关于C++无法根据STL容器类型进行流控,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26727313/