考虑以下功能:
template <class T>
constexpr /* something */ f(T&& x) {
// do something
}
并且假设我想根据传递给名为myfunction
的函数的转发参数的类型来做sfinae。实现这一目标的一种方法是:
template <class T>
constexpr auto f(T&& x) -> decltype(myfunction(std::forward<T>(x))) {
// do something
}
而不是这样做,有没有办法在模板级别执行此操作:
// This code won't compile
template <class T, class R = decltype(myfunction(std::forward<T>(x)))>
constexpr R f(T&& x) {
// do something
}
除了我无法访问x
之外,所以这段代码无法编译。有没有办法只根据T
(可能使用std::declval
)来实现这一目标?
注意:这不是一个X / Y问题,它只是一个例子来说明这种情况发生的地方:我不知道如何在不访问变量的情况下进行转发SFINAE,因为对我来说{{1}的行为仍然有点神秘。
答案 0 :(得分:5)
是的,std::declval
确实是关键:
template <class T, class R = decltype(myfunction(std::declval<T>()))>
constexpr R f(T&& x) {
// do something
}
这将是SFINAE out或R
将是选择myfunction
的任何重载的返回类型。
你的问题让我觉得你需要复习参考折叠的工作原理;我建议在该领域阅读(this似乎是一个很好的起点)。
答案 1 :(得分:4)
std::forward()
与此问题无关。 constexpr
也没有。因此,让我们从super basic开始,这是一个只通过值返回其参数的函数:
template <class T>
auto f(T x) -> decltype(x);
当然,我们可以使用T
,但这太简单了。现在的问题是,我们如何在保持SFINAE的同时将其提升为模板参数(在那里明显没有可能的替换失败,但请耐心等待):
template <class T, class R = decltype(x)>
R f(T x);
所以这不起作用,因为还没有x
(或者更糟糕的是,在名称查找找到的其他地方还有一些不相关的x
)。我们可以在trailing-return-type中使用参数名称,因为它们在范围内,但是我们不能在默认模板参数中将它们用作表达式-SFINAE的一部分,因为它们还不在范围内。
但由于这些是模板参数,我们并不关心他们的值。我们只关心他们的类型。这不是评估表达式。所以我不需要x
,我需要与x
具有相同类型的内容。第一步可能是:
template <class T, class R = decltype(T{})>
R f(T x);
只要T
是默认构造的,这就有效。但是我写了一个模板,我不想对我不需要制作的类型做出假设。相反,我可以做类似的事情:
template <class T> T make(); // never defined
template <class T, class R = decltype(make<T>())>
R f(T x);
现在我们有一个T
类型的任意表达式,我们可以在decltype
中使用默认模板参数。虽然,我们仍然对make()
有点限制 - 但有些类型您无法通过功能(例如数组)返回值,因此事实证明更有用的是添加引用。我们需要一个不太可能碰撞的名称而不是make
:
template <class T>
add_rvalue_reference<T> declval();
template <class T, class R = decltype(declval<T>())>
R f(T x);
这正是std::declval<T>
的要点 - 在未评估的上下文中为您提供类型为T
的表达式。
回到原来的问题。我们使用与decltype(x)
到decltype(declval<T>())
相同的思维过程,但只是将其应用于不同的表达式。我们x
取代myfunction(std::forward<T>(x))
而不是myfunction
。也就是说,我们使用与我们的参数相同的类型调用template <class T, class R = decltype(myfunction(std::declval<T&&>()))>
R f(T&& x);
:
std::declval<T&&>
但是由于参考折叠规则,std::declval<T>
实际上与template <class T, class R = decltype(myfunction(std::declval<T>()))>
R f(T&& x);
功能相同,所以我们可以写一下:
echo "<ul class='logad' >
<li class='o'>Olá," . $current_user->user_firstname . "</li>
<li class='d'>
<a href='https://3brow.com/minha-conta' class='ver'>Ver minha conta</a>
<a href='https://3brow.com/minha-conta/Sair/' class='sair'>Sair</a></li>
</ul>";
} else {
echo "<ul class='ent'>
<li><a href='#''>Entrar</a></li>
<li><a href='#''>Registrar</a></li>"
. do_action( 'wooc_save_extra_register_fields' ) . "</ul>";
}