有一次我意识到我希望能够编写这样的代码而不重复代码:
template<std::size_t N>
std::ostream& operator<< (std::ostream& o, const vector_type<N>& vector)
{
if constexpr (passed_by_value<typename vector_type<N>::value_type>)
{
for (const auto val : vector)
{
o << val << ' ';
}
}
else
{
for (const auto& val : vector)
{
o << val << ' ';
}
}
return o;
}
示例中的重复代码是
o << val << ' '
(或者可能是整个循环)。
当然,我知道为了避免代码重复,我们可以引入一个包含代码的函数。但这并不是我真正想要的解决方案。我希望它简单明了。
我在示例中使用
if constexpr
的原因是我希望我的模板函数能够处理值类型的容器和引用类型的容器。所以在一个街区我做 const auto
,而在另一个街区 - const auto&
。
如果我们能够实现一个行为如下的类型
super_type
那就太好了:
int passed_by_value = 100;
std::string passed_by_ref = "abcdefghijklmnop";
super_auto value = passed_by_value; // works like auto
super_auto value = passed_by_ref; // works like auto&
const super_auto value = passed_by_value; // works like const auto
const super_auto value = passed_by_ref; // works like const auto&
因此我们可以编写以下代码,该代码既适用于值类型也适用于引用类型:
for (const super_auto val : vector)
{
o << val << ' ';
}
这看起来与转发引用类似,但它并不总是引用,因此转发引用似乎对我们没有帮助。
所以问题是我们如何实现我所描述的逻辑?我有什么地方弄错了吗?或者 std lib 中有任何解决方案吗?
std::conditional
可以根据编译时 bool 生成类型。
template<std::size_t N>
std::ostream& operator<< (std::ostream& o, const vector_type<N>& vector)
{
using value_type = typename vector_type<N>::value_type;
using super_auto = std::conditional_t<
passed_by_value<typename vector_type<N>::value_type>,
value_type,
value_type& >;
for (const super_auto val : vector)
{
o << val << ' ';
}
return o;
}
也就是说,这种复杂性不太可能给您带来任何好处。
下面的代码清晰有效地完成了相同的工作。
template<std::size_t N>
std::ostream& operator<< (std::ostream& o, const vector_type<N>& vector)
{
for (const auto& val : vector)
{
o << val << ' ';
}
return o;
}