静态 constexpr 变量可以用作模板参数吗
can a static constexpr variable be used as a template argument
我有以下代码可以在较旧的 gcc 上编译,但不能在版本 6 上编译(适用于 -std=c++1z)。 Clang 也拒绝了它,说对象 val 没有正确的链接类型。我不明白其中的区别。指针类型的 constexpr 变量不是应该或多或少透明地工作吗?我在允许它工作的语法中缺少什么吗?或者这是否违反了标准的某些部分?
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
static constexpr t_voidfn val = &fn;
s<val> x;
}
另一方面,这个有效。
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
s<&fn> x;
}
第一个片段在 C++17 中是正确的,但在 C++14 和 11 中不正确。
对于 C++14,[temp.arg.nontype]/1 表示:
A template-argument for a non-type, non-template
template-parameter shall be one of:
[...]
- a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal
linkage or a function with external or internal linkage, including
function templates and function template-ids but excluding
non-static class members, expressed (ignoring parentheses) as
&
id-expression, where the id-expression is the name of an object or function, except that the &
may be omitted if the name refers to a
function or array and shall be omitted if the corresponding
template-parameter is a reference; or
- a constant expression that evaluates to a null pointer value (4.10); or
- a constant expression that evaluates to a null member pointer value (4.11); or
- a pointer to member expressed as described in 5.3.1; or
- a constant expression of type
std::nullptr_t
.
(我只包含了与指针和成员指针直接相关的项目符号。)
基本上,您示例中的函数地址必须严格表示为&fn
或fn
。
C++11 包含基本相同的措辞,只是在 11 和 14 之间的缺陷报告中引入了一些说明:
对于 C++17,由于采用了论文 N4268 (rationale in N4198),限制已经放宽。相应的第(2)段现在说:
A template-argument for a non-type template-parameter shall be a
converted constant expression (5.20) of the type of the
template-parameter. For a non-type template-parameter of reference or
pointer type, the value of the constant expression shall not refer to
(or for a pointer type, shall not be the address of):
- a subobject (1.8),
- a temporary object (12.2),
- a string literal (2.13.5),
- the result of a
typeid
expression (5.2.8), or
- a predefined
__func__
variable (8.4.1).
[ Note: If the template-argument represents a set of overloaded
functions (or a pointer or member pointer to such), the matching
function is selected from the set (13.4). — end note ]
N4198 包含对每个项目符号的很好解释。
我有以下代码可以在较旧的 gcc 上编译,但不能在版本 6 上编译(适用于 -std=c++1z)。 Clang 也拒绝了它,说对象 val 没有正确的链接类型。我不明白其中的区别。指针类型的 constexpr 变量不是应该或多或少透明地工作吗?我在允许它工作的语法中缺少什么吗?或者这是否违反了标准的某些部分?
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
static constexpr t_voidfn val = &fn;
s<val> x;
}
另一方面,这个有效。
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
s<&fn> x;
}
第一个片段在 C++17 中是正确的,但在 C++14 和 11 中不正确。
对于 C++14,[temp.arg.nontype]/1 表示:
A template-argument for a non-type, non-template template-parameter shall be one of:
[...]
- a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as
&
id-expression, where the id-expression is the name of an object or function, except that the&
may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or- a constant expression that evaluates to a null pointer value (4.10); or
- a constant expression that evaluates to a null member pointer value (4.11); or
- a pointer to member expressed as described in 5.3.1; or
- a constant expression of type
std::nullptr_t
.
(我只包含了与指针和成员指针直接相关的项目符号。)
基本上,您示例中的函数地址必须严格表示为&fn
或fn
。
C++11 包含基本相同的措辞,只是在 11 和 14 之间的缺陷报告中引入了一些说明:
对于 C++17,由于采用了论文 N4268 (rationale in N4198),限制已经放宽。相应的第(2)段现在说:
A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
- a subobject (1.8),
- a temporary object (12.2),
- a string literal (2.13.5),
- the result of a
typeid
expression (5.2.8), or- a predefined
__func__
variable (8.4.1).[ Note: If the template-argument represents a set of overloaded functions (or a pointer or member pointer to such), the matching function is selected from the set (13.4). — end note ]
N4198 包含对每个项目符号的很好解释。