【问题标题】:Instantiating a template class with NULL argument使用 NULL 参数实例化模板类
【发布时间】:2012-09-29 02:09:22
【问题描述】:

我从一堆其他 Stackoverflow 线程(如 this)中了解到,模板参数是在编译时评估的。 此外,非类型模板参数应该是常量表达式、整数表达式或指向具有外部链接的对象的指针。

而且,我没有在 Makefile 的 g++ 命令中使用 --std=c++0x。

那么,是否可以用 NULL 作为参数来实例化模板类?

// I have a template class like this - 
template<class T, T invalidVal, int e> class A
{ 
    static inline bool dummy(T value) 
    {
       return 0;
    }
}

#define MY_INVALID_VAL ((void *)0)

// Now I want create class from the above template class with 
// T=void*, invalidVal=NULL & e=0 
typedef A<void *, MY_INVALID_VAL, 1> ClassA;

以上代码在 MS Visual Studio 2008 上编译良好。 在 g++ 上 - 我收到错误 - “转换为整数或枚举类型以外的类型不能出现在常量表达式中”

我在谷歌搜索后尝试了一些选项 -

声明“extern void *MY_INVALID_VAL;”在头文件中 - 包含它并执行 无效 MY_INVALID_VAL=NULL;在模板实例化之前。 在这种情况下,我收到错误“MY_INVALID_VAL 不是类型 'void' 的有效模板参数,因为它不是常量指针”

所以我的问题是—— 不使用 c++0x 标准就没有办法用 NULL 参数实例化模板类吗?

谢谢!

编辑:

感谢所有 cmets 并感谢您引用标准草案中的确切部分。

只列出我尝试过的东西 -

1) 直接传递“0”是行不通的。 我得到的错误是 - “无法将 '0' 转换为模板参数 void *”

2) 声明静态 const void *my_null=0;并且传递 my_null 不起作用。 它给出了错误 - “my_null 不能出现在常量表达式中”

3) 尝试了其中一个 cmets 中建议的指向空对象的指针(空对象模式)方法 见下文-

class my_null
{
 public:
     my_null() { my_null_ptr = NULL; }
     void * get() { return my_null_ptr; }
 private:
    void *my_null_ptr;
};
my_null my_null_obj;
my_null *ptr = &my_null_obj;

typedef A<void *, (void *)ptr, 1> ClassA;

我仍然收到错误 - “ptr 不能出现在常量表达式中”

所以现在这让我想知道 - 我应该传递什么值才能使其工作? 或者有没有可能使它工作? (我的意思是一种不涉及使用 c++11 std 的方式) 我还没有找到一个可以成功编译的值。

任何帮助表示赞赏(并且需要:-P)!

作为旁注,我想问的另一件事是 - 是否有任何指针值可以用于非类型模板参数?

【问题讨论】:

  • 您是否尝试过只传递 0 而没有强制转换作为参数?
  • 我做到了 - 第一次 - 但后来它说 - 无法将“0”转换为模板参数“void *”。因此包括了类型转换。

标签: c++ templates g++


【解决方案1】:

C++98 说非类型模板参数应该是其中之一

  • 整数或枚举类型的整数常量表达式;或
  • 非类型模板参数的名称;或
  • 具有外部链接的对象或函数的名称,包括函数模板和函数template-ids,但不包括非静态类成员,表示为id-expression;或
  • 具有外部链接的对象或函数的地址,包括函数模板和函数template-ids,但不包括非静态类成员,表示为&id-expression如果名称指的是函数或数组,则 & 是选项;或
  • 指向成员的指针,如 5.3.1 中所述。

空指针不属于此列表的任何项,因此将空指针作为非类型模板参数传递是无效的。

C++11 将此列表更新为

  • 对于整数或枚举类型的非类型模板参数模板参数类型的转换常量表达式(5.19);或
  • 非类型模板参数的名称;或
  • 一个常量表达式 (5.19),它指定具有静态存储持续时间和外部或内部链接的对象或具有外部或内部链接的函数的地址,包括函数模板和函数 template-ids 但不包括非静态类成员,表示(忽略括号)为 & id-expression,但如果名称指代函数或数组,则 & 可以省略,如果对应的 template-parameter 是一个参考;或
  • 计算结果为空指针值的常量表达式 (4.10);或
  • 计算结果为空成员指针值的常量表达式 (4.11);或
  • 指向成员的指针,如 5.3.1 中所述。

更新后的要求确实涵盖了空指针。因此,要将空指针用作非类型模板参数,您必须使用 C++11。

【讨论】:

  • 使用空对象的地址(如在空对象模式中)作为标记值是 C++03 可能的解决方法。
  • 好的,所以我知道我不能将 NULL 作为非类型模板参数传递。但我应该能够通过指针仪式?我在另一个 cpp 文件中将一个变量定义为 extern const int a=0;在具有此模板类的文件中,我将其声明为 extern const int a;但是我不能将 (void *)&a 作为模板参数传递!有什么建议吗?
  • 外部链接并不意味着它必须被标记为extern。我相信您遇到的问题是不允许强制转换为 void*。
  • 谢谢,我刚刚向 Microsoft 提交了一个错误,因为 Visual Studio 在禁用语言扩展时仍然拒绝 null 作为参数,无论项目是否设置为 C++17
【解决方案2】:

试试这个:

static const void* my_null_pointer = 0;
typedef A<void *, my_null_pointer, 1> ClassA;

类似的东西在 MSVC 和 gcc 上也适用于我。 将 0 作为模板参数传递 应该 也可以。

typedef A<void *, 0, 1> ClassA;

【讨论】:

  • 感谢您的评论。直接输入“0”不起作用-我收到错误-“无法将“0”转换为模板参数“void *”。使用静态 const void * 也不起作用 - 它给出了错误 - 'my_null_pointer' 不能出现在常量表达式中。
  • 你用的是什么版本的gcc?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 2013-10-28
  • 1970-01-01
  • 2014-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多