C++17 中有条件启用的成员函数
Conditionally enabled member functions in C++17
假设类型可以有Foo
、Bar
、Baz
方法,我们有类型特征来检查它。例如。对于 Foo
我们有 HasFoo
:
template <class Type>
constexpr bool DetectFoo (decltype (std::declval<Type> ().Foo ())*) { return true; }
template <class Type>
constexpr bool DetectFoo (...) { return false; }
template <class Type>
constexpr bool HasFoo = DetectFoo<Type> (nullptr);
让我们写一个Wrapper<Type>
class模板,转发Type
的属性有或没有这些方法。对于任何 Type
应满足以下条件:
Wrapper<Type> w;
应该编译,因为我们还没有调用方法。
w.X ();
应该编译 iff HasX<Type>
,因为 X
= Foo
、Bar
、Baz
.
HasX<Wrapper<Type>> == HasX<Type>
应该成立,因为 X
= Foo
、Bar
、Baz
.
要有条件地启用 Wrapper
中的方法,在 C++20 中有一个明确的方法:
template <class Type>
struct Wrapper {
void Foo ()
requires HasFoo<Type>;
};
但是在早期的 C++ 标准中没有概念怎么办?我想出了以下想法(参见 live demo):
template <class Type>
struct Wrapper {
template <bool dummy = true, class = std::enable_if_t<HasFoo<Type> && dummy>>
void Foo ();
};
This answer 说它格式错误,NDR,但我不明白解释。这真的是病态的吗,NDR?
您的密码是 well-formed.
链接的答案是指[temp.res.general]/8.1
:
The validity of a template may be checked prior to any instantiation. ... The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template ... and the template is not instantiated, ...
在这里,我们所说的“模板”是Foo
。
我认为这可以有两种解释:
(1) 我们可以认为 Wrapper<A>::Foo
和 Wrapper<B>::Foo
是同一个模板(对于每个 A
、B
)。然后,Wrapper
的模板参数的存在使得 enable_if_t
true
中的条件足以使代码 well-formed.
(2) 我们也可以认为 Wrapper<A>::Foo
和 Wrapper<B>::Foo
是 不同的 模板(对于 A != B
)。然后,如果 Wrapper
存在这样一个无法实例化 Foo
的模板参数,您的代码将是 ill-formed NDR。但它永远不会发生,因为你总是可以将每个模板参数的 HasFoo
专门化为 true
!
无论如何,我认为 (1) 是预期的解释。 [temp.res.general]/8.1
的目的不是妨碍您,而是通过尽可能早地验证模板来帮助您。我从未见过编译器使用第二种解释。
假设类型可以有Foo
、Bar
、Baz
方法,我们有类型特征来检查它。例如。对于 Foo
我们有 HasFoo
:
template <class Type>
constexpr bool DetectFoo (decltype (std::declval<Type> ().Foo ())*) { return true; }
template <class Type>
constexpr bool DetectFoo (...) { return false; }
template <class Type>
constexpr bool HasFoo = DetectFoo<Type> (nullptr);
让我们写一个Wrapper<Type>
class模板,转发Type
的属性有或没有这些方法。对于任何 Type
应满足以下条件:
Wrapper<Type> w;
应该编译,因为我们还没有调用方法。w.X ();
应该编译 iffHasX<Type>
,因为X
=Foo
、Bar
、Baz
.HasX<Wrapper<Type>> == HasX<Type>
应该成立,因为X
=Foo
、Bar
、Baz
.
要有条件地启用 Wrapper
中的方法,在 C++20 中有一个明确的方法:
template <class Type>
struct Wrapper {
void Foo ()
requires HasFoo<Type>;
};
但是在早期的 C++ 标准中没有概念怎么办?我想出了以下想法(参见 live demo):
template <class Type>
struct Wrapper {
template <bool dummy = true, class = std::enable_if_t<HasFoo<Type> && dummy>>
void Foo ();
};
This answer 说它格式错误,NDR,但我不明白解释。这真的是病态的吗,NDR?
您的密码是 well-formed.
链接的答案是指[temp.res.general]/8.1
:
The validity of a template may be checked prior to any instantiation. ... The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template ... and the template is not instantiated, ...
在这里,我们所说的“模板”是Foo
。
我认为这可以有两种解释:
(1) 我们可以认为 Wrapper<A>::Foo
和 Wrapper<B>::Foo
是同一个模板(对于每个 A
、B
)。然后,Wrapper
的模板参数的存在使得 enable_if_t
true
中的条件足以使代码 well-formed.
(2) 我们也可以认为 Wrapper<A>::Foo
和 Wrapper<B>::Foo
是 不同的 模板(对于 A != B
)。然后,如果 Wrapper
存在这样一个无法实例化 Foo
的模板参数,您的代码将是 ill-formed NDR。但它永远不会发生,因为你总是可以将每个模板参数的 HasFoo
专门化为 true
!
无论如何,我认为 (1) 是预期的解释。 [temp.res.general]/8.1
的目的不是妨碍您,而是通过尽可能早地验证模板来帮助您。我从未见过编译器使用第二种解释。