[cpp]请问gcc 3.x下的一个模板问题
Wu Yongwei
adah at sh163.net
Thu May 11 23:14:17 CST 2006
经在 comp.lang.c++.moderated 上的讨论,我现在可以很确定地说,GCC 的行为
是符合 C++98 标准的,而 MSVC 的行为则否。
除了上次引用的 14.7.3/15 外,主要应当看 3.2/5:
There can be more than one definition of a class type (clause 9),
enumeration type (7.2), inline function with external linkage (7.1.2),
class template (clause 14), non-static function template (14.5.5),
static data member of a class template (14.5.1.3), member function
template (14.5.1.1), or template specialization for which some template
parameters are not specified (14.7, 14.5.4) in a program provided that
each definition appears in a different translation unit...
完全特化不在可重复出现的定义之列。
如果我写代码的话,我通常会这样做:
// 在 config.h 中
#ifndef HAS_NONSTD_SPECIALIZED_TMPL_STATIC_DATA_MBR_DEF
#if defined(_MSC_VER)
#define HAS_NONSTD_SPECIALIZED_TMPL_STATIC_DATA_MBR_DEF 1
#else // GCC or other standard-conformant compilers
#define HAS_NONSTD_SPECIALIZED_TMPL_STATIC_DATA_MBR_DEF 0
#endif
在程序的其它位置,则使用 HAS_NONSTD_SPECIALIZED_TMPL_STATIC_DATA_MBR_DEF
宏来决定代码的组织。这样,既有合理的缺省行为,又可以不修改代码、仅仅在编
译时定义宏来改变代码的行为。
吴咏炜
Wu Yongwei wrote:
> 昨天晚上没有在编译器上充分测试,今天测试了一下,结果还有点令我惊讶。目前
> 我无法写出在 MSVC8 和 GCC 下都能正常工作的代码!你原先的写法在 MSVC8 下
> (以及最新版本的 Digital Mars C++ 编译器)能工作,在 GCC 下能通过的写法是:
>
> 头文件中:
>
> template <typename DataType>
> class FMC
> {
> ...
> };
>
> template <>
> const double FMC<double>::Epsilon;
>
> 某一个 .cpp 文件中:
>
> 包含头文件
> template <>
> const double FMC<double>::Epsilon = static_cast<double>(0.0000000001);
>
> 其它 .cpp 文件中只需包含头文件即可。即特化在头文件中需要声明,但不应定义。
>
> MSVC6 下我没找到一种写法可以在所有情况下正常工作。
>
> 个人倾向于 GCC 是正确的。但是 8230; 8230;我不能百分百确认。我想到
> comp.lang.std.c++ 上去问一下,如果有结果,再告诉你。
>
> 关于宏的可变参数问题,如果你想寻找 GCC 的解决方案的话,google 一下 8220;gcc
> macro __VA_ARGS__ 8221;。我不知道任何跨平台的解决方案。
>
> 吴咏炜
>
> rockie wrote:
>
>>吴咏炜,你是对的,已经在gcc 3.x下过了,非常感谢。
>>还有一个问题,也是郁闷了很久的,关于宏的参数问题。
>>即如何让一个宏支持参数数目可变的参数,如函数的...参数
>>#ifdef ENABLE_LOG
>>
>>#include "logger.h"
>>enum ChannelTag
>>{
>> CT_NONE = 0,
>> CT_ERROR,
>> CT_PARSE,
>> CT_SEND,
>> CT_SENSE,
>> CT_NOTIFY,
>> //...
>> CT_MAX // append channel tags before this line
>>};
>>
>>extern Logger LOGGER; //Logger是个容器,重载了->操作符
>>#define DoLog LOGGER->Log
>>//Log方法声明:
>>//void Log(IndexType channel, const char* szFmt, ...);
>>//使用例子:DoLog(CT_MEASURE, "FLAG1 not seen.");
>>
>>//#define AssertLog(x, y, z) if(!(x)){DoLog(y,z)} //这个是不行的,不能支持多参数
>>//要问的问题:
>>//如何定义一个宏使得可以实现如下功能?即
>>//AssertLog(断言条件, CT_MEASURE, "FLAG1 not seen.");
>>//并可支持可变数目的参数
>>//AssertLog(断言条件, CT_PARSE, "Unknown vision sensation at time[%f]: [%s]", time, sense);
>>
>>#else //NOT ENABLE_LOG
>>
>>#ifdef _WIN32
>> #define DoLog(x) NULL
>> // #define AssertLog(x) NULL
>>#else
>> #define DoLog(...) NULL
>> // #define AssertLog(...) NULL
>>#endif //
>>
>>#pragma warning(disable: 4002)
>>
>>#endif //ENABLE_LOG
>>
>>------------------
>>rockie
>>2006-05-03
>>
>>-------------------------------------------------------------
>>发件人:Wu Yongwei
>>发送日期:2006-05-03 00:24:43
>>收件人:C++ Discuss Group
>>抄送:
>>主题:Re: [cpp]请问gcc 3.x下的一个模板问题
>>
>>rockie wrote:
>>
>>
>>>大家好, 有个问题难住了。
>>>以下程序打开注释在vc6, vs05下可以通过编译,不知道为什么在gcc 3.x下编译不通过。
>>>谢谢指教。
>>>
>>>template <typename DataType>
>>>class FMC
>>>{
>>>public:
>>> ...
>>> static const DataType Epsilon;
>>> ...
>>>private:
>>> FMC() {}
>>>};
>>>
>>>/*
>>>template <>
>>>const float FMC<float>::Epsilon = static_cast<float>(0.000001);
>>>
>>>template <>
>>>const double FMC<double>::Epsilon = static_cast<double>(0.0000000001);
>>>*/
>>>
>>>template <typename DataType>
>>>const DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);
>>>
>>>错误提示是multiple definition
>>>
>>>--------------
>>>rockie
>>>rockie at student.dlut.edu.cn
>>>2006-05-02
>>
>>
>>我估计你出问题的原因是把被注释掉的代码放到了头文件中,并在多处包含了该头
>>文件。解决方法是把这些代码移到(只编译、连接一次的)一个 .cpp 文件中。
>>
>>我认为 GCC 的做法是符合 C++ 标准的。C++1998 标准的 14.7.3.15 这么写的:
>>
>>An explicit specialization of a static data member of a template is a
>>definition if the declaration includes an initializer; otherwise, it is
>>a declaration. [Note: there is no syntax for the definition of a static
>>data member of a template that requires default initialization.
>>
>> template<> X Q<int>::x;
>>
>>This is a declaration regardless of whether X can be default initialized
>>(8.5). ]
>>
>>也就是说,被注释掉的这两段代码被视作定义而不是声明。在头文件定义类成员变
>>量当然是要出问题的。错误 multiple definition 也就正常了。
>>
>>吴咏炜
More information about the Cpp
mailing list