Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么指针类型转换对模板非类型参数不起作用_C++_Templates_C++11 - Fatal编程技术网

C++ 为什么指针类型转换对模板非类型参数不起作用

C++ 为什么指针类型转换对模板非类型参数不起作用,c++,templates,c++11,C++,Templates,C++11,我有以下代码: template <const char *p> struct A{}; template <int i> struct E{}; extern constexpr int i = 0; constexpr float f = 0.f; extern constexpr char c = 0; int main(int argc, const char *argv[]) { A<&c> b; //works A<(co

我有以下代码:

template <const char *p>
struct A{};

template <int i>
struct E{};

extern constexpr int i = 0;
constexpr float f = 0.f;
extern constexpr char c = 0;
int main(int argc, const char *argv[])
{
  A<&c> b; //works
  A<(const char *)(&i)> a; //Error: could not convert template argument ‘(const char*)(& i)’ to ‘const char*’
  E<(int)f> e; //works
  return 0;
}
因此,不仅
不允许重新解释演员阵容
。使用
A至于“标准这么说”的答案,请查看注释

真正的问题是为什么不允许这样做

在模板参数中断然拒绝类型转换非常有意义,因为您真正感兴趣的是模板参数的值<但是,strong>类型转换可能会变得任意复杂,并且不会强制为
constexpr
s。标准(显然)对内置(基本)类型没有例外。

请注意,您的
E
示例也被
clang
驳斥,原因如下:

错误:“int”类型的非类型模板参数不是整型常量表达式


为什么gcc允许这样做是可疑的,但我假设它允许您使用可以显式声明的
constepr
s。请注意,这不可能在
A

+1个有趣问题的参数列表中隐藏
i
的地址。我记得“const expression”中不允许使用指针强制转换。但我可能错了,如果我是对的,它只回答了编译器为什么不允许它的直接问题,我相信在常量表达式中不允许使用
reinterpret\u cast
,但我不确定C风格的cast是否会碰巧解析为
reinterpret\u cast
。尽管该标准在将地址常量表达式的概念定义为一种特殊类型时遇到了麻烦常量表达式,它没有使用§14.3.2/1中描述非类型模板参数的概念:模板参数必须是整数或静态存储持续时间[…]表示为
&id expression
[…]的对象地址。后一种措辞似乎排除了任何类型的强制转换。14.3.2/5为指针类型的非类型模板参数提供了有效的模板参数。但是,(int*)0和nullptr都是“指向int的指针”类型的非类型模板参数的有效模板参数
,因此这可能是编译器的错误。虽然我不确定。@tenfour它在C++03,14.3.2/1“具有外部链接的对象或函数的地址…”中是有意义的。“这不可能在A.的参数列表中隐藏i的地址”是什么意思,因为
ab
实际上是编译的,它采用
c
的地址?它与
clang
一起工作吗?@DanqiWang:我的意思是,你不能在参数列表之外使用额外的(例如全局)变量来确定
I
的地址,然后将其作为参数传递——这意味着我们不能在这里欺骗编译器<代码>A b在
clang
中编译得很好,这是应该的。但是为什么某些类型强制转换允许用于地址类型的常量表达式(§5.19/3,例如,您可以合法地声明一个单独的表达式
constepr const char*pi=static_cast(static_cast(&i));
,但是,当常量表达式用作模板参数时,会显式排除相同类型的类型强制转换吗?常量表达式(包括地址常量表达式)的设计是为了在编译时对其求值(尽管它们不一定总是以这种方式实现)。对于模板参数来说,这还不够好吗?@jogojapan:这一点很好。我们得问问标准化委员会。
struct Base{};
struct Derived : public Base {};

template <const Base *p>
struct A{};

extern constexpr Base base = {};
extern constexpr Derived derived = {};
A<&base> a; //works
A<(const Base*)&derived> b; //error: could not convert template argument ‘(const Base*)(& derived)’ to ‘const Base*’
  A<(const Base*)(0)> b; // error: could not convert template argument ‘0u’ to ‘const Base*’