利用C++模板元能否实现动态指定数据类型?

zzccode 2009-02-25 04:16:54
用过gdal的人应该都知道,RasterIO读取影像的结果保存在一个void数组中,当我们使用这个数组的时候,一般需要告诉编译器这个数组到底是个什么类型,如下例:
MYErrors fun(void* img,int size,MyType type)
{
switch(type)
{
case MyByte:
for(int i = 0;i < size;i++)
{
*((BYTE*)img + offset) = i;
}
break;
case MyFloat:
for(int i = 0;i < size;i++)
{
*((float*)img + offset) = i;
}
break;
default:
break;
}
}
对于这种情况,我如何才能去掉这个switch语句?!
尝试了一下模板元的方法,如下:
template<MyType T>
struct IfThenElse {};

template<>
struct IfThenElse<MyByte>
{
typedef byte ResultT;
};

template<>
struct IfThenElse<MyFloat>
{
typedef float ResultT;
};

template<MyType T>
struct GET_TYPE
{
typedef typename IfThenElse<T>::ResultT ResultT;
};


MYErrors fun(void* img,int size,MyType type)
{
for(int i = 0;i < size;i++)
{
*((GET_TYPE<type>::ResultT*)img + offset) = i;//这一行报错,说“a local variable cannot be used as a non-type argument”
}
}

错就错在GET_TYPE<type>,type如果换成常量,比如MyByte就是对的,或者换成外部常量也是对的,变量就不行。

请问各位高手,还有什么别的办法能去掉函数中的switch吗?模式设计中说switch最好不要出现在代码中,对我现在的代码而言是很有道理的,现在我只需要byte和float,那如果以后我要添加long和double呢?而且类似的函数还有很多很多,难道我每个函数都要去改吗?

所以,希望高手们不吝赐教,万分感谢!


...全文
788 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
icosagon 2009-11-11
  • 打赏
  • 举报
回复
初学者看到有些书籍把模板用的出神入化,就以为模板无所不能。
forster 2009-11-11
  • 打赏
  • 举报
回复
高级语言有泛型的概念
模板只是静态编译出来的 不是动态的
yshuise 2009-11-11
  • 打赏
  • 举报
回复
如下:
// csdn_09_11_11.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
using namespace std;
struct byte;
template<typename T>
struct Mytype{
static void fun(void* img, int size)
{
cout<<"没有这种类型"<<endl;
}
};
template<>
struct Mytype<byte>
{
static void fun(void* img, int size)
{
cout<<"byte类型,在这儿实现"<<endl;
}
};
template<>
struct Mytype<float>
{
static void fun(void* img, int size)
{
cout<<"float类型,在这儿实现"<<endl;
}
};
template<typename T>
void fun(void* img,int size)
{
Mytype<T>::fun(img,size);
}

int _tmain(int argc, _TCHAR* argv[])
{
fun<char>(0,0);
fun<float>(0,0);
fun<byte>(0,0);
return 0;
}

没有这种类型
float类型,在这儿实现
byte类型,在这儿实现
请按任意键继续. . .
spdelphi 2009-11-11
  • 打赏
  • 举报
回复
这个问题确实很难,模板类或函数可以解决问题,但是这样用很不方便,因为有很多图像处理算法不希望公开源码,模板就解决不了这个问题了,另外,用模板还需要创建好多个类型的实例,用起来也很不方便。
继续讨论阿!!!~~~
winnuke 2009-11-11
  • 打赏
  • 举报
回复
查表吧。
一个静态数组,每个成员对应type以及一个相应的处理函数。
通过某种方案将你的tpe映射到一组连续的数字,然后直接用该数字在数组里找到对应的便宜的成员的函数,执行之。
xuruilll 2009-11-11
  • 打赏
  • 举报
回复
关注,我也在用GDAL,也有同样的问题。
用模板或继承感觉都不能很好的解决问题。
哪位高人给指点一下啊。
hz_yck 2009-06-18
  • 打赏
  • 举报
回复
失误,注释打成反斜杠了
hz_yck 2009-06-18
  • 打赏
  • 举报
回复
# define fun(img, size, type)({ \
GET_TYPE <type>::ResultT * __img = img; \
int __size = size; \
MyError __err; \
\ \\do something...
__err; \
})
hz_yck 2009-06-18
  • 打赏
  • 举报
回复
改正宏函数
Eleganz 2009-06-18
  • 打赏
  • 举报
回复
www.librose.org,这个就是开源的基于GDAL的图像处理的开源模板库,RoseEngineXero类的EngineStart()函数里有自动枚举数据类型的源码
zzccode 2009-03-05
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 yshuise 的回复:]
什么叫模板元?模板元就是静态,编译时期,不是执行。所以打消这个念头。
[/Quote]

大家都已经知道了,所以还是给点建议吧。。。
zzccode 2009-03-05
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 yi_jun_jun 的回复:]
楼主,可能没有看过 < <现代C++设计>> < <C++设计新思维>>吧!
建议你去看一下,问题可解决。
[/Quote]

你说的也也不对,那两本书一个中文版一个英文版,写得几乎一样,相当于翻译。里面最靠谱的就是我在一楼写的方法,但我早就实践过不行。
zzccode 2009-03-05
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 abc_46664 的回复:]
楼主的Fun函数可不可以这么写?

struct Test
{
typedef int MyInt;
}
template <class T>
MYErrors fun(void* img,int size)
{
for(int i = 0;i < size;i++)
{
*((T*)img + offset) = i;
}
}

fun <Test::MyInt>(img,size);
不知对否
[/Quote]

显然不对,不能解决问题。。。
yshuise 2009-03-05
  • 打赏
  • 举报
回复
什么叫模板元?模板元就是静态,编译时期,不是执行。所以打消这个念头。
abc_46664 2009-03-04
  • 打赏
  • 举报
回复
楼主的Fun函数可不可以这么写?

struct Test
{
typedef int MyInt;
}
template<class T>
MYErrors fun(void* img,int size)
{
for(int i = 0;i < size;i++)
{
*((T*)img + offset) = i;
}
}

fun<Test::MyInt>(img,size);
不知对否
zzccode 2009-03-02
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 lhwiskoala 的回复:]
关注类似问题很久了
好像一直没有合适的解决方法

有人说C# java里的反射可以解决,但C++里没有
对这个我不是很了解。

我的问题也类似,
就是有很多很多的类型,对应的是一系列的数字
输入一个数字,就得到对应的类型。
现在只能switch,好长好长好长的swtich。
非常的不爽,还有很多其它的问题。
[/Quote]

呵呵,C#确实可以,但是你也知道,做图像处理用C#怎么行呢,那个效率实在是有一点点差距,兄弟如果有什么好的解决办法记得告诉我一声啊,万分感谢。
zzccode 2009-03-02
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 arong1234 的回复:]
其实这很容易用模板+重载实现啊

对于你的代码,你可以做如下修改

C/C++ code
template <typename T>
void process(T& a)
{
a = a+ T(1);
}
void process(string & s)
{
s.append(_T(' '));
}


template <typename T>
void fun(T* img,int count)
{
int i;
for(i=0; i<count; i++) {
process(img[i]);
};
}






这样对于每个可能的T你写一个process函数,…
[/Quote]

您的代码我看了,不知道我理解对不对,我说说我的理解啊:
如果我现在有两副图像,要对它进行四种操作(如加减乘除等),而我要支持七种数据类型(byte、int、float。。。),如果按照您的代码来写,在下面是只需要写四个操作的模板函数就可以了,每个函数有两个typename,因为两幅影像数据类型可能不同,如果再复杂点,我还要指定运算时的数据类型,那么每个模板函数就有三个typename,如果再复杂点,我还要指定输出图像的数据类型,那么每个模板函数就有四个typename。按照您的代码处理方法,在底层,无论多少个typename都没有问题,直接加T1、T2、T3...就可以了,但是您想过在上层我怎么解决给这个函数赋值吗?
我分析了一下您的代码,您分析的时候没有考虑到void*怎么到类型T的,而现在的困难正是在这个地方,底层如果都用T表示,那么上层就麻烦了。我们用模板类来说明吧,假设一个模板类是用于图像的四则运算的,而用户要求能支持不同数据类型的输入影像,同时要指定计算时的数据类型(例如两个byte类型影像做除法很明显不能直接用byte类型作为计算时采用的数据,因为128/233=0,这很明显是错的),还要指定输出数据类型(两幅byte相加之后我要输出一个int类型,因为255+255会溢出)。那么这个类可以这么表示:
template<typename T1,typename T2,typename T3,typename T4>
class A
{
//具体的加减乘除函数
....

}

那么上层用户给你两幅影像,告诉了你这两幅影像的数据类型,指定了计算类型和输出类型,您如何初始化A这个类?
假设四种数据类型分别是int、bye、int、float
那么就是A<int,byte,int,float> a;
但如果是byte,byte,float,int呢,可能的情况还有很多很多(如果我支持7种数据类行,那么可能的情况最多能达到7*7*7*7种!)
因此,用户给你一个标记(int类型或者string都行,告诉你数据类行),我如何才能根据这个标记,省事省代码的把gdal读取到的void*数组强制转换用户指定的数据类行呢?您有办法吗?

另外,您说的同根类,我百度google了一下,好像这个名词只是出自您之口,好像没别人说过了,能写段代码解释一下吗?就我上面举的四则运算的例子,您认为应该怎么利用同根类处理?万分期盼!

zzccode 2009-03-02
  • 打赏
  • 举报
回复
您的代码我看了,不知道我理解对不对,我说说我的理解啊:
如果我现在有两副图像,要对它进行四种操作(如加减乘除等),而我要支持七种数据类型(byte、int、float。。。),如果按照您的代码来写,在下面是只需要写四个操作的模板函数就可以了,每个函数有两个typename,因为两幅影像数据类型可能不同,如果再复杂点,我还要指定运算时的数据类型,那么每个模板函数就有三个typename,如果再复杂点,我还要指定输出图像的数据类型,那么每个模板函数就有四个typename。按照您的代码处理方法,在底层,无论多少个typename都没有问题,直接加T1、T2、T3...就可以了,但是您想过在上层我怎么解决给这个函数赋值吗?
我分析了一下您的代码,您分析的时候没有考虑到void*怎么到类型T的,而现在的困难正是在这个地方,底层如果都用T表示,那么上层就麻烦了。我们用模板类来说明吧,假设一个模板类是用于图像的四则运算的,而用户要求能支持不同数据类型的输入影像,同时要指定计算时的数据类型(例如两个byte类型影像做除法很明显不能直接用byte类型作为计算时采用的数据,因为128/233=0,这很明显是错的),还要指定输出数据类型(两幅byte相加之后我要输出一个int类型,因为255+255会溢出)。那么这个类可以这么表示:
template<typename T1,typename T2,typename T3,typename T4>
class A
{
//具体的加减乘除函数
....

}

那么上层用户给你两幅影像,告诉了你这两幅影像的数据类型,指定了计算类型和输出类型,您如何初始化A这个类?
假设四种数据类型分别是int、bye、int、float
那么就是A<int,byte,int,float> a;
但如果是byte,byte,float,int呢,可能的情况还有很多很多(如果我支持7种数据类行,那么可能的情况最多能达到7*7*7*7种!)
因此,用户给你一个标记(int类型或者string都行,告诉你数据类行),我如何才能根据这个标记,省事省代码的把gdal读取到的void*数组强制转换用户指定的数据类行呢?您有办法吗?

另外,您说的同根类,我百度google了一下,好像这个名词只是出自您之口,好像没别人说过了,能写段代码解释一下吗?就我上面举的四则运算的例子,您认为应该怎么利用同根类处理?万分期盼!
arong1234 2009-02-26
  • 打赏
  • 举报
回复
如果这种动态类型是运行时才知道的,那么你应该把所有的MyType 对应的类型用同根类包装起来,然后用虚函数和继承来实现,要跳出“先检测类型,在做动作”这种思维,用更适合的方法做事情。一种方法在一种语言中很有效率(如C#的反射)在另一种语言中不一定很有效,虽然可能也能做到。要尽量用这种语言native支持的特性做事情。要根据要解决的问题去找合适的方法,而不是先选定方法再看要解决啥问题
arong1234 2009-02-26
  • 打赏
  • 举报
回复
其实这很容易用模板+重载实现啊

对于你的代码,你可以做如下修改

template <typename T>
void process(T& a)
{
a = a+ T(1);
}
void process(string & s)
{
s.append(_T(' '));
}


template <typename T>
void fun(T* img,int count)
{
int i;
for(i=0; i<count; i++) {
process(img[i]);
};
}




这样对于每个可能的T你写一个process函数,就可以处理每种类型了(这只是思想,和你原来的代码功能可能不一样,实在看不出你代码在干吗)
加载更多回复(11)

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧