增强了 C++ 中的“自动”[已关闭]

Strengthened 'auto' in C++ [closed]

提问人:Capy Maths 提问时间:10/2/2023 更新时间:10/2/2023 访问量:132

问:


想改进这个问题吗?通过编辑这篇文章添加详细信息并澄清问题。

上个月关闭。

曾几何时,我意识到我希望能够在不复制代码的情况下编写这样的代码:

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 << ' '

当然,我知道为了避免代码重复,我们可以引入一个包含代码的函数。然而,这并不是我真正想要的解决方案。我希望它简单明了。

我在示例中使用的原因是我希望我的模板函数能够同时处理值类型的容器和 ref 类型的容器。所以在一个块中我这样做,而在另一个块中 - .if constexprconst autoconst 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&

因此,我们可以编写以下代码,这些代码既适用于 value- 类型,也适用于 ref 类型:

for (const super_auto val : vector)
{
    o << val << ' ';
}

这看起来与转发 ref 相似,但它并不总是 ref,因此转发 ref 似乎对我们没有帮助。

那么问题来了,我们如何实现我所描述的逻辑呢?我在哪里弄错了吗?或者 std lib 中是否有任何解决方案?

C++ 模板 STL 迭代器 AUTO

评论

4赞 273K 10/2/2023
我不明白你为什么需要,该块运行良好,在这两种情况下都是最佳的。ifelse
4赞 Drew Dormann 10/2/2023
for (const auto& val : vector)很可能是所有类型的最佳方法。
3赞 chrysante 10/2/2023
我在示例中使用 if constexpr 的原因是我希望我的模板函数能够处理值类型的容器和 ref 类型的容器 - 没有包含引用的 C++ 容器,至少没有标准容器。
1赞 273K 10/2/2023
预处理优化 复制 4 字节(通常)比创建 8 字节(通常)引用更容易 - 1。事实并非如此。2. std::vector 的迭代器返回一个引用。
1赞 Drew Dormann 10/2/2023
@CapyMaths 这是一个不正确的假设。“另一个层次的去引用”是语言中的抽象。它不会强制编译的机器代码效率降低。亲眼看看 - 对于您编写的循环的两个版本,生成的程序集是相同的。您正在尝试的复杂性不会带来任何好处。

答:

4赞 Drew Dormann 10/2/2023 #1

std::conditional 可以生成基于编译时布尔值的类型。

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<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;
}

评论

0赞 Ted Lyngmo 10/2/2023
由于您制作了别名,因此可以简化为 - 并且可能会使其更通用一些。passed_by_value<typename vector_type<N>::value_type>passed_by_value<value_type>using value_type = std::iterator_traits<decltype(std::begin(vector))>::value_type;
1赞 Drew Dormann 10/2/2023
@TedLyngmo好渔获!感谢分享。
0赞 Capy Maths 10/2/2023
感谢您的建议。这看起来不错,但我确实想要一些更隐含的东西。使用需要指定类型。然而,对我来说,更多的是通过隐含的推导来省略类型规范。因此,只有当您提供实现所描述的推导的方法而没有任何额外的本地 typedef 或其他东西时,我才会感到满意。可能是一些结构或类,我会在不了解其后台的类型操作的情况下包含和使用。std::conditionalautosuper_auto
1赞 Ted Lyngmo 10/3/2023
@CapyMaths 如果使用 那么,即使对于不同类型的普通 C 数组也会被推导出来。由于你想根据你的类型特征使用不同的类型,我认为你不会比使用德鲁在这个答案中所示更简单。using value_type = std::iterator_traits<decltype(std::begin(vector))>::value_typevalue_typestd::conditional