关于这个指向成员函数的指针类型模板参数,标准是怎么说的?是我的代码有误,还是 MSVS 16.6 有问题?
What does the standard say about this pointer-to-member-function type template parameter? Is my code wrong, or is MSVS 16.6 buggy?
下面是一些适用于 GCC、Clang 和 MSVS 的代码(至少,那些当前在 Compiler Explorer 上可用的版本):
template <typename T, auto T::* MemberPtr>
struct Foo
{
Foo(const T& e) : _e(e) {}
void operator()() const
{
(_e.*MemberPtr)();
}
private:
const T& _e;
};
struct Bar
{
void baz() const {}
auto bind()
{
using BindingType = Foo<Bar, &Bar::baz>;
return BindingType(*this);
}
};
int main()
{
Bar i;
i.bind();
}
从 v16.6.1 开始,但是,MSVS 拒绝它:
Severity Code Description Line
Error C2973 'Foo': invalid template argument 'int' 23
Error E2886 cannot deduce 'auto' template parameter type "auto T::*" from "void (Bar::*)()" 21
Error C2440 'specialization': cannot convert from 'overloaded-function' to 'auto Bar::* ' 22
Error C3535 cannot deduce type for 'auto Bar::* ' from 'int' 23
Error C2440 'specialization': cannot convert from 'int' to 'int Bar::* ' 23
通过去掉 MemberPtr
的 T::*
限定符,该版本中的代码可以是 "fixed";所以:
template <typename T, auto MemberPtr>
标准对此有何规定? VS v16.6.1 是否引入了新的回归,或者它现在正在诊断总是被巧妙破坏的代码?
parameter/argument 组合有效
[temp.param]
4 A non-type template-parameter shall have one of the following
(optionally cv-qualified) types:
- ...
- a type that contains a placeholder type.
[temp.arg.nontype]
1 If the type of a template-parameter contains a placeholder
type, the deduced parameter type is determined from the type of the
template-argument by placeholder type deduction. If a deduced
parameter type is not permitted for a template-parameter declaration
([temp.param]), the program is ill-formed.
现在,auto T::*
是一个包含占位符类型的类型。 placholder type deduction 在
形式的变量声明中工作得很好
auto Bar::* foo = &Bar::baz;
所以 VS v16.6.1 没有拒绝这种非类型模板参数的业务。
下面是一些适用于 GCC、Clang 和 MSVS 的代码(至少,那些当前在 Compiler Explorer 上可用的版本):
template <typename T, auto T::* MemberPtr>
struct Foo
{
Foo(const T& e) : _e(e) {}
void operator()() const
{
(_e.*MemberPtr)();
}
private:
const T& _e;
};
struct Bar
{
void baz() const {}
auto bind()
{
using BindingType = Foo<Bar, &Bar::baz>;
return BindingType(*this);
}
};
int main()
{
Bar i;
i.bind();
}
从 v16.6.1 开始,但是,MSVS 拒绝它:
Severity Code Description Line
Error C2973 'Foo': invalid template argument 'int' 23
Error E2886 cannot deduce 'auto' template parameter type "auto T::*" from "void (Bar::*)()" 21
Error C2440 'specialization': cannot convert from 'overloaded-function' to 'auto Bar::* ' 22
Error C3535 cannot deduce type for 'auto Bar::* ' from 'int' 23
Error C2440 'specialization': cannot convert from 'int' to 'int Bar::* ' 23
通过去掉 MemberPtr
的 T::*
限定符,该版本中的代码可以是 "fixed";所以:
template <typename T, auto MemberPtr>
标准对此有何规定? VS v16.6.1 是否引入了新的回归,或者它现在正在诊断总是被巧妙破坏的代码?
parameter/argument 组合有效
[temp.param]
4 A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
- ...
- a type that contains a placeholder type.
[temp.arg.nontype]
1 If the type of a template-parameter contains a placeholder type, the deduced parameter type is determined from the type of the template-argument by placeholder type deduction. If a deduced parameter type is not permitted for a template-parameter declaration ([temp.param]), the program is ill-formed.
现在,auto T::*
是一个包含占位符类型的类型。 placholder type deduction 在
auto Bar::* foo = &Bar::baz;
所以 VS v16.6.1 没有拒绝这种非类型模板参数的业务。