假设类型可以有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>
类模板,它转发具有或不具有这些方法的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++标准中该怎么办呢?我提出了以下想法(见现场演示(:
template <class Type>
struct Wrapper {
template <bool dummy = true, class = std::enable_if_t<HasFoo<Type> && dummy>>
void Foo ();
};
这个答案说这是不正确的,NDR,但我不明白解释。这真的不正规吗,NDR?
您的代码格式良好。
链接的答案指[temp.res.general]/8.1
:
模板的有效性可以在任何实例化之前进行检查。。。程序格式错误,无需诊断,如果:
--无法为模板生成有效的专用化。。。并且模板没有被实例化。。。
这里;模板";我们说的是CCD_ 23。
我相信这可以用两种方式来解释:
(1( 我们可以认为Wrapper<A>::Foo
和Wrapper<B>::Foo
是相同的模板(对于每个A
、B
(。然后,Wrapper
的模板自变量的存在使得enable_if_t
中的条件true
足以使代码良好地形成。
(2( 我们还可以将Wrapper<A>::Foo
和Wrapper<B>::Foo
视为不同的模板(对于A != B
(。然后,如果Wrapper
存在这样一个无法实例化Foo
的模板参数,那么您的代码将是格式错误的NDR。但这永远不会发生,因为对于每个模板参数,您总是可以将HasFoo
专门化为true
!
无论如何,我认为(1(是预期的解释。[temp.res.general]/8.1
的目的不是妨碍您,而是通过尽早验证模板来帮助您。我从未见过编译器使用第二种解释。