【问题标题】:Using decltype to get an expression's type, without the const使用 decltype 获取表达式的类型,没有 const
【发布时间】:2013-10-14 15:43:57
【问题描述】:

考虑以下程序:

int main ()
{
    const int e = 10;

    for (decltype(e) i{0}; i < e; ++i) {
        // do something
    }
}

使用 clang(以及 gcc)编译失败:

decltype.cpp:5:35: error: read-only variable is not assignable
    for (decltype(e) i{0}; i < e; ++i) {
                                  ^ ~

基本上,编译器假设i 必须是const,因为e 是。

有没有办法我可以使用decltype 来获取e 的类型,但删除const 说明符?

【问题讨论】:

  • @KerrekSB auto 在这里也不起作用。无论e 是否为int,它都会给我一个int
  • for (auto end = e, i = 0; i != end; ++i)...
  • @KerrekSB 如果e 不是int,我得到inconsistent deduction for ‘auto’
  • @KerrekSB 这不一定有效,因为在“逗号分隔的自动声明”中推导出的所有类型都必须相同。
  • @ChristianRau:auto end = e, i {} 呢?

标签: c++ c++11 decltype


【解决方案1】:

为此,我更喜欢auto i = decltype(e){0};。它比使用type_traits 简单一些,而且我觉得它更明确地指定了您希望将变量初始化为e 类型的0 的意图。

我最近经常使用Herb's "AAA Style",所以这可能只是我的偏见。

【讨论】:

  • 这太棒了。它以简洁的语法回答了我所追求的真正问题。
  • 这会额外调用delctype(e) 的任何构造函数吗?还是那是 C++11 修复的那种东西?
  • decltype(e){} 会更笼统。
【解决方案2】:

使用std::remove_const:

#include<type_traits>
...
for (std::remove_const<decltype(e)>::type i{0}; i < e; ++i)

【讨论】:

  • std::remove_const_t&lt;decltype(e)&gt; i{0} 使用 C++14
  • 很高兴知道这一点。感谢您的提示。
【解决方案3】:

你也可以使用std::decay:

#include<type_traits>
...
for (std::decay<decltype(e)>::type i{}; i < e; ++i) {
  // do something
}

【讨论】:

  • 应该是typename std::decay&lt;decltype(e)&gt;::type。 C++14 添加了一个别名来缩短它,std::decay_t&lt;decltype(e)&gt;
【解决方案4】:

尚未提及的解决方案:

for (decltype(+e) i{0}; i < e; ++i)

原始类型的 Prvalues 已剥离 const;所以+eint 类型的纯右值,因此decltype(+e)int

【讨论】:

  • 这会强制类型为int,而不是从泛型类型中删除const。不过,很酷的把戏!
  • @CameronTacklind 我猜你指的是正在应用的整数提升——小于int 的类型被提升为int,但其他类型保持不变。如果elong,那么ilong(不是int)。
【解决方案5】:

我更喜欢 range-for。模拟很容易。

#include <iostream>

template< typename T >
struct range_t
{
    struct iter
    {
        T operator * ()const noexcept { return n;}
        iter& operator ++()noexcept{ ++n; return *this;}
        friend
        bool operator != (iter const& lhs, iter const& rhs)noexcept
        { return lhs.n != rhs.n;}

        T n;
    };

    iter begin()const noexcept {return {b};}
    iter end() const noexcept{ return {e};}
    T b, e;
};
template< typename T > range_t<T>  range(T b, T e){ return {b,e}; }

int main()
{
    const int e = 10;

    for( auto i : range(0,e) )
    {
        std::cout << i << ' ';
    }
    return 0;
}

【讨论】:

  • 我不喜欢这种方法的是这样一个简单应用程序的样板代码。现在,它在其他情况下也很有用。
  • 我看不到编译器为此创建的代码与普通的 for 循环一样有效。 @greendiod 你只需要声明一次样板文件。
  • @LucBloom 启用优化后,g++ 为基于范围的 for 和普通 for 输出相同的程序集:godbolt
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-01
  • 2012-08-28
  • 2016-11-22
  • 2011-06-25
相关资源
最近更新 更多