考虑这个程序:
template <int F(), int N = F()>
void f() { }
constexpr int g() { return 1; }
int main() { f<g>(); }
Run Code Online (Sandbox Code Playgroud)
这有效吗?编译器是否需要查看模板定义时间,这F可能会引用一个constexpr函数,因此默认参数N可能有效吗?
gcc和clang接受这个,但是Intel 1在模板定义时拒绝模板函数,因为F()它不是一个常量表达式.f<g, g()>()如果默认参数被删除,英特尔确实接受,因此很明显它理解它g()通常可用于常量表达式.
我不清楚标准说的是什么.很明显(C++ 11 [expr.const] p2)
调用除
constexpr文字类或constexpr函数的构造函数之外的函数
呈现一个非常量的表达式,但我不清楚这是否适用于此.在模板定义时,它肯定似乎适用,因为F未声明为constexpr函数,但同时,模板定义时的错误应该仅在模板没有可能的有效实例化时被诊断出来,并且这里似乎确实存在有效的实例化.
我可以看到两个答案的论据,所以我感到困惑.这个问题有明确的答案吗?
1.使用当前版本的英特尔编译器重新测试表明它的工作正常,因此可能是英特尔开发人员认为它是一个错误并且已经修复了它.这是一个巨大的暗示,代码是有效的.尽管如此,根据标准得到一个确定的答案仍然会很好.
template <int * ip> struct test {};
struct q {
static int a;
int b;
constexpr q(int b_) : b(b_) {}
};
int i;
constexpr q q0(2);
int main()
{
constexpr test<&i> t1; // Works fine
constexpr test<&q::a> t2; // Works
constexpr test<&q0.b> t3; // Does not work; address of non-static member?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
尽管&q0.b在编译期间已知模板参数,但上述代码中的t3声明仍然失败.一些谷歌搜索显示标准不允许这样做(第14.3.2节):
[注意:数组元素的地址和非静态类成员的名称或地址是不可接受的模板参数.
X <&m.m> x4; //错误:非静态元素的地址
那么,尽管全局变量的非静态成员的地址在编译时是唯一的以及已知的,但为什么这个标准明确禁止这一点呢?
在C++ 11中,我使用constexpr函数作为模板参数的默认值 - 它看起来像这样:
template <int value>
struct bar
{
static constexpr int get()
{
return value;
}
};
template <typename A, int value = A::get()>
struct foo
{
};
int main()
{
typedef foo<bar<0>> type;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
G ++ 4.5和4.7编译它,但Clang ++ 3.1没有.来自clang的错误消息是:
clang_test.cpp:10:35: error: non-type template argument is not a constant expression
template <typename A, int value = A::get()>
^~~~~~~~
clang_test.cpp:17:19: note: while checking a default template argument used here
typedef foo<bar<3>> type;
~~~~~~~~~^~
clang_test.cpp:10:35: note: undefined function …Run Code Online (Sandbox Code Playgroud)