Fortran Coder

标题: 参数化类型如何绑定 [打印本页]

作者: lookbook    时间: 2018-11-8 13:23
标题: 参数化类型如何绑定
本帖最后由 lookbook 于 2018-11-8 13:23 编辑

各位大佬好,代码如下:

      module m_a
         implicit none

         type :: bar(p, q)
            integer, kind :: p=4
            integer, len  :: q=10
            real(kind=p),dimension(q) :: x
         contains
            procedure,pass(this) :: barsub
         end type bar

      contains
         subroutine barsub(this)
            class(bar), intent(in) :: this
            write (*,*) this%x
         end subroutine barsub
      end module


gfortran编译错误如下:
       procedure,pass :: barsub
               1
Error: Argument ‘this’ of ‘barsub’ with PASS(this) at (1) must be of the derived-type ‘bar’

小白还望大佬们赐教,谢谢!




作者: liudy02    时间: 2018-11-8 14:43
参数化派生类型是个坑,
目前还不知道有哪个编译器能很好的支持所有参数化派生类型的标准,
我反正是放弃找别的路子
我也坐等大佬看有什么办法没有……
作者: lookbook    时间: 2018-11-8 16:38
liudy02 发表于 2018-11-8 14:43
参数化派生类型是个坑,
目前还不知道有哪个编译器能很好的支持所有参数化派生类型的标准,
我反正是放弃找 ...

感觉你就是大佬呀。。。
作者: liudy02    时间: 2018-11-8 16:42
lookbook 发表于 2018-11-8 16:38
感觉你就是大佬呀。。。

你看我的级别积分什么的就知道不是啊……
和你一样的萌新菜鸟……
作者: 楚香饭    时间: 2018-11-9 00:55
kind的参数必须要编译时确定,不能假定
len的参数可以假定。
所以,多个kind,就要写多个函数。

[Fortran] 纯文本查看 复制代码
module m_a
  implicit none
  type :: bar(p, q)
    integer, kind :: p=4
    integer, len  :: q=10
    real(kind=p),dimension(q) :: x
  contains
    procedure:: barsub => barsub4 , barsub8
  end type bar

contains

  subroutine barsub4(this)
    type(bar(p=4,q=*)), intent(in) :: this
    write (*,*) this%q , this%p
  end subroutine barsub4
  
  subroutine barsub8(this)
    type(bar(p=8,q=*)), intent(in) :: this
    write (*,*) this%q , this%p
  end subroutine barsub8
  
end module

Program Main
  use m_a
  type(bar(4,30)) :: x4_30
  type(bar(4,20)) :: x4_20
  type(bar(8,30)) :: x8_30
  type(bar(8,20)) :: x8_20
  call x4_30%barsub()
  call x4_20%barsub()
  call x8_30%barsub()
  call x8_20%barsub()
End Program Main  

作者: liudy02    时间: 2018-11-9 10:17
本帖最后由 liudy02 于 2018-11-9 10:18 编辑
楚香饭 发表于 2018-11-9 00:55
kind的参数必须要编译时确定,不能假定
len的参数可以假定。
所以,多个kind,就要写多个函数。

因为IVF和gfortran都没有支持对参数化派生类型中(Len=:)对象的Allocate语句
所以原来我已经觉得参数化派生类型废掉了,
版主却向我展示了它的另外一种用法,确实可以用一种类型涵盖事实上的多种数据
不过这里我有一点点疑惑:
不同的Kind在这里的处理方式实际上还是用的不同的函数
并没有让程序写起来变得更为简洁
从减小单个文件或单个Module的角度,怎么感觉还是写成不同的TYPE封装进不同的Module文件更合适呢
这种参数化派生类型的优势或者是巧妙应用是什么呢……
作者: 楚香饭    时间: 2018-11-9 11:16
不同的kind,需要用不同的函数。这是肯定的,毕竟二进制代码(指令)完全不同。
如果你有很高的通用编程需求,可以考虑用C++,模板会让通用编程更方便。
(事实上,模板也是产生了多个目标代码的函数的)

Fortran在OOP方面还刚刚起步,尚需时间和契机来成熟。
这主要还是取决于需求,至少,我还没有太多这方面的需求。

至于哪个合适,就要自己斟酌了。写成不同type,可能在维护性上会有欠缺。
PS:我在实际应用中,参数化type也很少使用。
作者: liudy02    时间: 2018-11-9 12:38
本帖最后由 liudy02 于 2018-11-9 12:40 编辑
楚香饭 发表于 2018-11-9 11:16
不同的kind,需要用不同的函数。这是肯定的,毕竟二进制代码(指令)完全不同。
如果你有很高的通用编程需 ...

原来如此,版主的解释让我终于明了Kind参数和Len参数为什么在编程上有不同之处了
写成不同的Type寻找上应该是要困难点,所以同一类型不同kind就要分别去找文件
另外如果对与这几种Kind的相关过程有一致性要求,确实也容易顾此失彼,不过反正自己一个人维护的话还好
但是写在不同文件里边,从编辑灵活性上还是好些啊
非常感谢版主的理论解释和经验分享,对我相当具有启发性

作者: lookbook    时间: 2018-11-9 15:58
liudy02 发表于 2018-11-9 12:38
原来如此,版主的解释让我终于明了Kind参数和Len参数为什么在编程上有不同之处了
写成不同的Type寻找上应 ...

其实有一个方法,只需要多一个module就行。就是在最底层定义一个kind常量,然后每个module都包含使用它即可。

module style
integer,parameter :: nnn=8
end module

module another

type anything
real(kind=nnn) :: a,b
balabala.....
.......
这样的话,关于绑定的函数也只要写一遍就行,但记得更改nnn之后要clean一下,然后再make。
我是这样处理的。
作者: lookbook    时间: 2018-11-9 16:00
楚香饭 发表于 2018-11-9 00:55
kind的参数必须要编译时确定,不能假定
len的参数可以假定。
所以,多个kind,就要写多个函数。

大佬就是大佬,学习了,我去试试。
作者: liudy02    时间: 2018-11-9 16:20
lookbook 发表于 2018-11-9 15:58
其实有一个方法,只需要多一个module就行。就是在最底层定义一个kind常量,然后每个module都包含使用它即 ...

哈哈,这个果然是个好办法,根据自己实际用哪个来决定Kind常数
不过这里有一个问题是如果某个程序里同时需要用多种Kind的版本肿么办呢?
感觉上这样做的话似乎实际用的过程中还需要弄个中间产物
比如写个Make文件,可以自动生成各种kind的.o文件和.mod文件
每次定义Type的文件修改了之后,make一下就可以自动产生这三个文件
凡是需要用到这个Type的程序,每次copy最新的.o和.mod文件就可以了
嗯,可惜我最近要写的那个东西需要用到BLAS,要不然就能马上用你这一招了,非常感谢
另外,你这写的不完整吧,定义kind常数的不应该写成:
integer,parameter :: nnn=kind(0.0d0)
或者:
integer,parameter :: Selected_Real_Kind(14)吗?
作者: lookbook    时间: 2018-11-10 13:52
我的理解是,不同的编译器可能对kind的表示不同,所以才会有selected_real_kind(),我用的是gfotran,4就代表real,8就代表double。
我测试了一下:
module style
      implicit none
      integer,parameter :: nnn=8
end module

use style
implicit none
real(kind=nnn) :: a
     
a=1d0
print*,a,kind(a)

end
结果是:
   1.0000000000000000                8

所以是可行的。
不过我在编写程序的时候是严格的,是使用了Selected_Real_Kind()的,
希望它的移植性能更好。
不知道这么理解对不对,如有错误千万不要怪我呀
作者: lookbook    时间: 2018-11-15 22:08
楚香饭 发表于 2018-11-9 00:55
kind的参数必须要编译时确定,不能假定
len的参数可以假定。
所以,多个kind,就要写多个函数。

版主您好,我去试了下,我的编译器(gfortran8)不行,错误提示是:
procedure:: barsub => barsub4 , barsub8
               1
Error: Non-polymorphic passed-object dummy argument of ‘barsub4’ at (1)
作者: liudy02    时间: 2018-11-16 22:31
lookbook 发表于 2018-11-15 22:08
版主您好,我去试了下,我的编译器(gfortran8)不行,错误提示是:
procedure:: barsub => barsub4 , ba ...

哈哈,版主也犯错了啊
把后面两个进程里对哑元定义的关键字TYPE换成CLASS应该就好了
作者: liudy02    时间: 2018-11-16 22:42
本帖最后由 liudy02 于 2018-11-16 22:44 编辑

顺便说句,我终于现实解决了之前说的想定义不同kind但是功能几乎一样的类型,
甚至包括不同的数据类型,例如有Real又有Complex的办法了,不过在LINUX下才好操作这个
此法既可以减小文件和module的大小,又可以保证所有定义各种派生类型的module的一致性
简单来说就是在一开始只写一个Module文件,在其开始时定义kind常数
Module当然采用Private语句,Type的数据成员和绑定进程基本也全Private,
只用Interface和operator暴露几个想要被引用的进程
然后写个sh脚本,自动copy出想要的几个文件名,
然后sh脚本里继续用sed命令逐个文件自动替换掉kind常数定义和定义的type类型名
写个含有program的主文件,啥都不用干,就是USE所有的module
最后写个makefile文件,将sh脚本的运行也加上去,让它能够用主文件和所有的module文件编译出个程序就OK
这样也能看出来哪里有错了,哈哈
作者: vvt    时间: 2018-11-17 09:36
配合预处理,确实能实现更多语法不方便做的事情。

比如 Qt 的 moc,扩展了 C++ 的功能
作者: weixing1531    时间: 2018-11-17 11:05
改变精度必然要重新编译代码
这种花哨功能不实用
作者: lookbook    时间: 2018-11-18 16:30
liudy02 发表于 2018-11-16 22:42
顺便说句,我终于现实解决了之前说的想定义不同kind但是功能几乎一样的类型,
甚至包括不同的数据类型,例 ...

嗯,是个好办法。
不过我现在不太让shell完成太多东西了,程序能自己解决的就尽可能不用shell(大概是我变懒了)。
你是不是对C++很熟啊,感觉使用Private属性还是很有用处的,我自己写的时候不太注意这个。
作者: lookbook    时间: 2018-11-18 16:30
vvt 发表于 2018-11-17 09:36
配合预处理,确实能实现更多语法不方便做的事情。

比如 Qt 的 moc,扩展了 C++ 的功能 ...

学习了,但是离开IDE是不是就不行了?
作者: lookbook    时间: 2018-11-18 16:35
weixing1531 发表于 2018-11-17 11:05
改变精度必然要重新编译代码
这种花哨功能不实用

嗯,改变精度必须要全部重新编译,这个问题给我的印象很深刻。

在一个程序里面,确实有可能性需要用到不同精度的同一个结构的自定义类型(虽然我都是统一精度的)。
这个时候参数化类型就能很方便的解决这个问题了。
作者: lookbook    时间: 2018-11-18 16:36
liudy02 发表于 2018-11-16 22:31
哈哈,版主也犯错了啊
把后面两个进程里对哑元定义的关键字TYPE换成CLASS应该就好了 ...

我都试过,并不可以。
作者: liudy02    时间: 2018-11-19 08:30
lookbook 发表于 2018-11-18 16:30
嗯,是个好办法。
不过我现在不太让shell完成太多东西了,程序能自己解决的就尽可能不用shell(大概是我 ...

像我这么马虎的人,真正实现封装可以避免因为马虎犯很多错啊……
作者: liudy02    时间: 2018-11-19 08:31
lookbook 发表于 2018-11-18 16:36
我都试过,并不可以。

啊,那真是奇怪,从编译报错看就是这个问题啊……
作者: vvt    时间: 2018-11-19 09:22
lookbook 发表于 2018-11-18 16:30
学习了,但是离开IDE是不是就不行了?

在编程的世界里,没有什么东西是离开IDE就不行的




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2