当 T==void 时如何最好地解决"void foo( const T& t = T() )"



我有一个函数,它有一个类型为T的选项参数。

template<typename T>  
void foo( const T& t = T() )  
{ t.stuff; }

这一切都很好,但我现在有一个场景,T变成void。在这种情况下,我期望一个无操作的空函数。我唯一可行的解决方案需要三个单独的声明,我有很多这样的方法:

template<typename T> 
void foo( const T& t)
{ t.stuff; }
template<typename T>
inline void foo() 
{ foo(T()); }
template<> 
inline void foo<void>() {}

理想情况下,我希望应该有一个更优雅的解决方案来重载"Void"函数,而不需要使用第三个声明?尤其是现在新的C++17解决了很多问题!一个更简洁、更短的语法可能会很好。。。

一个更简单的解决方案(因为只有两个重载(应该是这样的:

template<typename T>
void foo( const T& t = T() ) {
t.stuff;
}
template<typename T>
std::enable_if_t<std::is_void_v<T>>
foo() {}
// void foo(const T&); is the only viable overload for non-void T,
// since std::enable_if_t SFINAEs
// void foo(); is the only viable overload for void T,
// since const T& forms a reference to void

使用别名模板可以稍微缩短这一点,因为你经常使用这种模式:

template<typename T, typename TypeIfVoid = void>
using if_void = std::enable_if_t<std::is_void_v<T>, TypeIfVoid>;

template<typename T>
void foo(const T& t = T()) {
t.stuff;
}
template<typename T>
if_void<T> foo() {}

两个默认的模板参数可以做到这一点:

template<class T> using FallbackT = std::conditional_t<std::is_void_v<T>, int, T>;
template<class T = int&, class U = FallbackT<T>>
void foo(U const& t = U()) {
if constexpr (!std::is_void_v<T>)
t.stuff();
}

示例。

int&T的默认值,因此如果有人试图在没有模板参数或实际参数的情况下调用foo()(请尝试在示例中取消注释(,则编译失败(默认情况下在U()处构造引用(。

我在FallbackT别名模板中使用int,因为U只需要是默认可构造的东西——这对用户来说是不可见的。

如果你想变得花哨(并防止滥用(,你可以添加一个变体保护并使用闭包类型:

template<
class T = decltype([]{})&,
class...,
class U = std::conditional_t<std::is_void_v<T>, decltype([]{}), T>>
void foo(U const& t = U()) {
if constexpr (!std::is_void_v<T>)
t.stuff();
}

这里,可变保护防止明确指定U,例如foo<int, long>();闭包类型使得人们不可能通过任何其他方式用这些类型调用foo——这可能是不必要的。

理想情况下,我希望应该有一个更优雅的解决方案来重载"Void"函数,而不需要使用第三个声明?尤其是现在新的C++17解决了很多问题!一个更简洁、更短的语法可能会很好。。。

嗯。。。如果没有第三个声明,是的(您只能使用一个(。

更优雅。。。我想这是品味的问题。

更精确的语法。。。好我想差不多。

无论如何,我提出以下版本,基于if constexprstd::conditional_t

template <typename T,
typename U = std::conditional_t<std::is_same_v<T, void>,
int,
T>>
void foo (U const & u = U{})
{
if constexpr ( std::is_same_v<T, void> )
{ /* do nothing */ }
else
{ /* do u.stuff; */ }
}

最新更新