包含函数指针的 class 可以用作非类型模板参数吗?
Can a class containing a function pointer be used as a non-type template parameter?
考虑以下 class S
包含一个函数指针,以及一个 constexpr
对象 s
class 用 lambda 初始化:
struct S
{
void (*f) ();
};
constexpr S s { []{} };
现在,如果我使用 S
类型的非类型模板参数编写模板 X
,并像这样在 s
上实例化它:
template<S> struct X {};
using x = X<s>;
clang 编译代码,但 gcc 抱怨:
error: '<lambda()>::_FUN' is not a valid template argument of type 'void (*)()' because '<lambda()>::_FUN' is not a variable
using x = X<s>;
^
这是 program。
代码对我来说似乎没问题,但我不确定错误消息指的是什么。那么这段代码有效吗?
请注意,如果 X
具有指向 S
的引用类型的非类型模板参数,则两个编译器都接受代码,如下所示:
template<S const &> struct X {};
这个问题的灵感来自另一个类似的 。
代码有效。
A template-argument for a non-type template-parameter shall be a converted constant expression ([expr.const]) of the type of the template-parameter.
A converted constant expression of type T
is an expression, implicitly converted to type T
, where the converted expression is a constant expression and the implicit conversion sequence contains only [...]
(本例中没有隐式转换。)
A constant expression is [...] or a prvalue core constant expression whose value satisfies the following constraints:
- if the value is an object of class type, each non-static data member of reference type refers to an entity that is a permitted result of a constant expression,
- if the value is of pointer type, it contains [...] the address of a non-immediate function [...],
- if the value is of pointer-to-member-function type, [...],
- if the value is an object of class or array type, each subobject satisfies these constraints for the value.
An entity is a permitted result of a constant expression if [...] or if it is a non-immediate function.
(除了 consteval
之外的所有函数都是 non-immediate。[dcl.constexpr])
因此,s
是类型 S
的有效转换常量表达式。此外,它不受 [temp.arg.nontype]/3(仅适用于 pointer/reference 对象)的限制。
也就是说,s
是一个有效的模板参数。
I'm not sure what the error message is referring to
胡说八道
错误是从 invalid_tparm_referent_p
inside GCC. It was extracted from code for handling pointer to object type when class non-type template paramter was implemented (4be5c72) 发出的。显然,实施者忘记更新此功能以解决 pointer-to-function 案例。
我已将错误报告为 https://gcc.gnu.org/PR97700。
考虑以下 class S
包含一个函数指针,以及一个 constexpr
对象 s
class 用 lambda 初始化:
struct S
{
void (*f) ();
};
constexpr S s { []{} };
现在,如果我使用 S
类型的非类型模板参数编写模板 X
,并像这样在 s
上实例化它:
template<S> struct X {};
using x = X<s>;
clang 编译代码,但 gcc 抱怨:
error: '<lambda()>::_FUN' is not a valid template argument of type 'void (*)()' because '<lambda()>::_FUN' is not a variable
using x = X<s>;
^
这是 program。
代码对我来说似乎没问题,但我不确定错误消息指的是什么。那么这段代码有效吗?
请注意,如果 X
具有指向 S
的引用类型的非类型模板参数,则两个编译器都接受代码,如下所示:
template<S const &> struct X {};
这个问题的灵感来自另一个类似的
代码有效。
A template-argument for a non-type template-parameter shall be a converted constant expression ([expr.const]) of the type of the template-parameter.
A converted constant expression of type
T
is an expression, implicitly converted to typeT
, where the converted expression is a constant expression and the implicit conversion sequence contains only [...]
(本例中没有隐式转换。)
A constant expression is [...] or a prvalue core constant expression whose value satisfies the following constraints:
- if the value is an object of class type, each non-static data member of reference type refers to an entity that is a permitted result of a constant expression,
- if the value is of pointer type, it contains [...] the address of a non-immediate function [...],
- if the value is of pointer-to-member-function type, [...],
- if the value is an object of class or array type, each subobject satisfies these constraints for the value.
An entity is a permitted result of a constant expression if [...] or if it is a non-immediate function.
(除了 consteval
之外的所有函数都是 non-immediate。[dcl.constexpr])
因此,s
是类型 S
的有效转换常量表达式。此外,它不受 [temp.arg.nontype]/3(仅适用于 pointer/reference 对象)的限制。
也就是说,s
是一个有效的模板参数。
I'm not sure what the error message is referring to
胡说八道
错误是从 invalid_tparm_referent_p
inside GCC. It was extracted from code for handling pointer to object type when class non-type template paramter was implemented (4be5c72) 发出的。显然,实施者忘记更新此功能以解决 pointer-to-function 案例。
我已将错误报告为 https://gcc.gnu.org/PR97700。