C++17 中有条件启用的成员函数

Conditionally enabled member functions in C++17

假设类型可以有FooBarBaz方法,我们有类型特征来检查它。例如。对于 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 中的方法,在 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>::FooWrapper<B>::Foo 是同一个模板(对于每个 AB)。然后,Wrapper 的模板参数的存在使得 enable_if_t true 中的条件足以使代码 well-formed.

(2) 我们也可以认为 Wrapper<A>::FooWrapper<B>::Foo 不同的 模板(对于 A != B)。然后,如果 Wrapper 存在这样一个无法实例化 Foo 的模板参数,您的代码将是 ill-formed NDR。但它永远不会发生,因为你总是可以将每个模板参数的 HasFoo 专门化为 true

无论如何,我认为 (1) 是预期的解释。 [temp.res.general]/8.1 的目的不是妨碍您,而是通过尽可能早地验证模板来帮助您。我从未见过编译器使用第二种解释。