我有一个模板,我需要在其中使用从用户提供的类型派生的类型 T
在 noexcept
内说明符多次。在下面的示例中,我需要使用 T
的衰减类型多次。天真的方法是:
// in this case
template <typename T>
void foo(T&& t) noexcept( noexcept(typename std::decay<T>::type(std::forward<T>(t)))
&& noexcept(std::declval<typename std::decay<T>::type>() = std::forward<T>(t)))
{
typedef typename std::decay<T>::type DT;
/* ... */
}
需要重复typename std::decay<T>::type
所以常常显得过于冗长。我可以用 DT
替换整个表达式类型,但不幸的是,这仅在函数体中可用。
最简单的介绍DT
在函数体之前我能想到的是这样的:
template <typename T, typename DT = typename std::decay<T>::type>
void foo(T&& t) noexcept( noexcept(DT(std::forward<T>(t)))
&& noexcept(std::declval<DT>() = std::forward<T>(t)))
{
/* DT also available here... */
}
不过,仅仅为了这个目的而添加另一个模板参数感觉是错误的。所以,我的问题:
- 添加额外的默认模板参数是否有任何有害的副作用?
- 这被认为是不好的做法吗?
- 有没有其他方法可以引入
DT
以便它在noexcept
中可用说明符?
编辑:
在我看来,真正的问题并不是获得对 DT
的访问权。 ,但降低了 noexcept
的复杂性完全表达(因为它用于许多函数)。我在下面添加了一个答案,为此目的创建了一个自定义特征。
最佳答案
我觉得我无法回答第二个问题,即它是否被视为不良做法,因为我认为这些是根据具体情况做出的决定。对您有用的东西可能对其他人不起作用。
您应该了解的是备选方案。如果调用者认为他需要显式提供两个模板参数,则添加另一个默认模板参数会更改 API 并打开潜在的错误。这不太可能,AFAICS 通常不是一个大问题。 API 修改 OTOH 可能是个问题。
在这种情况下,您可能会考虑将 foo
变成 foo_impl
的转发器,并且只有 foo_impl
具有第二个默认模板参数。这通常有助于保持 API 清洁。如果您将 foo_impl
移动到匿名命名空间(或者移动到 private
第二个,如果这是在一个类中)编译器可能会也可能不会内联它,甚至生成的代码看起来像你的移动详细和明确的版本。
namespace
{
template <typename T, typename DT = typename std::decay<T>::type>
void foo_impl(T&& t) noexcept( noexcept(DT(std::forward<T>(t)))
&& noexcept(std::declval<DT>() = std::forward<T>(t)))
{
/* DT also available here... */
}
}
// clean API
template <typename T>
void foo(T&& t) noexcept(noexcept(foo_impl(std::forward<T>(t))))
{
return foo_impl(std::forward<T>(t));
}
关于c++ - 使用默认模板参数引入派生类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19043652/