【发布时间】:2014-12-30 21:08:24
【问题描述】:
以下是一个类的示例,它遍历 STL 容器并打印出每个元素,并为 main() 附加了初始化代码。
似乎编译器在编译时解析了整个 ContainerPrinterClass,并在到达传入的 STL 容器之一中的元素不支持的行时抛出错误,例如 element.first/element.second 类型为 @987654323 @ 在向量中。然而,它甚至不应该进入那个条件,因为流控制明确声明只输入它if (std::is_same<T, std::map<int, std::string>>::value) 是真的。
当映射被传递到打印函数并且编译器在else 条件中标记错误时,它试图打印元素,这是一个 std::pair 并且不能。但它甚至不应该处于 else 条件,因为如果传递了一个 map,执行将转到 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> ]
【问题讨论】:
-
为什么不为
std::map<int, std::string>提供printElementsInContainer的专业化? -
请注意,
for each是 C++ 的 Visual C++ 扩展,不是标准的。如果您正在寻找 C++11 容器迭代循环结构,它是for (auto & element : *container)。 (但是你为什么不通过引用传递你的容器呢?) -
编译时,所有代码路径都必须包含有效代码,因此当函数模板专门用于
std::vector时,尝试访问成员first和second不会编译。您可以根据std::is_same产生的true_type/false_type标记调度到分别处理map和vector情况的实现。最简单的解决方案是使用pretty printer -
if不是条件代码编译工具。
标签: c++ visual-c++ c++11 stl