C++如何区分容器模板和本机类型
C++ how to differentiate between template for container and native type
我有以下问题:
template<class T>
void set(std::string path, const T data)
{
stringstream ss;
ss << data << std::endl;
write(path, ss.str();
}
template<class T>
void set(std::string path, const T data)
{
std::stringstream ss;
for(typename T::const_iterator it = data.begin(); it < data.end(); ++it)
{
ss << *it;
if(it < data.end() -1 )
ss << ", ";
}
ss << std::endl;
write(path, ss.str());
}
我得到以下错误:
error: ‘template<class T> void myclass::set(std::string, T)’ cannot be overloaded
error: with ‘template<class T> void myclass::set(std::string, T)’
有没有办法区分容器类型和模板中的其他类型?
使用特征:
#include <type_traits>
template <typename T>
typename std::enable_if<is_container<T>::value>::type
set (std::string const & path, T const & container)
{
// for (auto const & x : container) // ...
}
template <typename T>
typename std::enable_if<!is_container<T>::value>::type
set (std::string const & path, T const & data)
{
std::ostringstream oss;
oss << data;
write(path, oss.str());
}
你可以在漂亮的打印机代码中找到合适的特征。
在C++03中,您可以使用一点SFINAE来为不同类型选择性地启用不同版本的函数:
#include <boost/type_traits.hpp>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
template<class T>
void set(typename boost::enable_if<boost::is_pod<T>, std::string>::type path, const T data)
{
std::cout << "POD" << std::endl;
stringstream ss;
ss << data << std::endl;
}
template<class T>
void set(typename boost::disable_if<boost::is_pod<T>, std::string>::type path, const T data)
{
std::cout << "Non-POD" << std::endl;
std::stringstream ss;
for(typename T::const_iterator it = data.begin(); it < data.end(); ++it)
{
ss << *it;
if(it < data.end() -1 )
ss << ", ";
}
ss << std::endl;
}
int main() {
int i;
float f;
std::vector<int> v;
set("", v);
set("", i);
set("", f);
}
我在这里使用boost是为了方便,但如果boost不是一个选项,你可以自己滚动,或者使用C++11。
is_pod
并不是你真正想要的,你可能想要一个is_container
特征,但这并不是微不足道的,你需要制作一个自己的特征,而is_pod
很好地近似了如何使用特征来选择性地启用函数作为简单的答案。
您可以在此处尝试替换失败不是错误(SFINAE)技术。
首先,您需要一个函数来确定一个类型是否有迭代器成员。。。
template <typename T>
struct Has_Iterator
{
template <typename>
static char test(...);
template <typename U>
static int test(typename U::const_iterator*);
static const bool result = sizeof test<T>(0) != sizeof(char);
};
在上面的代码中,C++标准要求使用test(typename U::const_iterator*)
,而不是模糊的"…"参数匹配,只要U
实际上是一个具有const_iterator
成员类型的结构/类。否则,您将出现"替换失败"——这不是停止编译的致命错误(因此为SFINAE),并且test(...)
满足了查找匹配函数的尝试。由于两个函数的返回类型不同,sizeof
运算符可以测试哪一个匹配,从而适当地设置result
布尔值。
然后,您可以将打印内容的请求转发给支持它们的模板专业。。。
template <typename T>
void print(const T& data)
{
printer<Has_Iterator<T>::result, T>()(data);
}
// general case handles types having iterators...
template <bool Has_It, typename T>
struct printer
{
void operator()(const T& data)
{
for (typename T::const_iterator i = data.begin(); i != data.end(); ++i)
std::cout << *i << ' ';
std::cout << 'n';
}
};
// specialisation for types lacking iterators...
template <typename T>
struct printer<false, T>
{
void operator()(const T& data)
{
std::cout << data << 'n';
}
};
正如我的前任所写的,你必须使用某种特质。你可能应该使用Boost,但如果你不想,你可以使用这样的东西(http://ideone.com/7mAiB):
template <typename T>
struct has_const_iterator {
typedef char yes[1];
typedef char no[2];
template <typename C> static yes& test(typename C::const_iterator*);
template <typename> static no& test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
template <bool> class bool2class {};
template <class T>
void set_inner(const std::string &path, T & var, bool2class<false> *) {
// T is probably not STL container
}
template <class T>
void set_inner(const std::string &path, T & var, bool2class<true> *) {
// T is STL container
}
template <class T>
void set(const std::string &path, T &var) {
set_inner(path, var, (bool2class<has_const_iterator<T>::value>*)0);
}
区分容器和简单数组不是一件容易的事,所以我在这里检查类型是否有const_iterator
。也许您还应该检查它是否有begin()
、end()
和其他您将在未来代码中使用的东西。
- 交叉编译器树莓派不完整类型,而本机编译器工作
- 如何在本机 c++ jni 中实现 java 类型数组
- 在非本机类型上具有多个条件的 GDB 断点
- 将Boost Multi_array转换为本机数组类型
- 操作方法:将 boost::endian 缓冲区类型转换回本机格式
- 警告C4150在尝试包装本机C 类时,指向不完整类型的指针删除
- 错误:尝试纯粹在 NDK C++ 的本机活动中使用 Open GL 时,无法解析类型 'EGL_DEFAULT_DISPLAY'
- Windows特定类型和本机类型C
- 从SQL Server返回C++本机客户端中的NULL数据类型
- 引用计数本机类型的C++模板
- C++如何区分容器模板和本机类型
- JNI——可以将复杂类型作为本机方法参数传递
- 如何在 Boost.ASIO 中分配已连接的本机套接字类型 (TCP)
- 各种数据类型的变量如何存储在C++(本机)二进制文件中
- 表示本机有符号和无符号整数大小的数据类型
- Java 编程语言中的数据类型如何映射到本机编程语言(如 C 和 C++)中的数据类型
- 对于多少种类型的 x86 处理器,Ngen 和 .net 本机一次创建本机代码
- 为什么我假设"string"不是本机 c++ 数据类型
- 如何在模板中进行从本机类型到用户定义类型的显式转换
- 像本机类型一样,没有隐式转换的整型