C++ 惰性评估是否有效/可优化?

C++ 惰性评估是否有效/可优化?,c++,gcc,visual-c++,clang,C++,Gcc,Visual C++,Clang,我发现惰性评估有很多用途,比如优化工具(例如) 另一个用途是语法糖。但是,在我以运行时开销为代价让代码看起来更干净之前,编译器知道如何优化这类东西吗?或者我应该只在潜在开销比不使用惰性评估更快的情况下使用它吗 下面是我的意思的一个例子。这不是我的实际用例,只是一个简单的非懒惰vs懒惰评估版本 // original template < class out, class in > out && lazy_cast( in && i

我发现惰性评估有很多用途,比如优化工具(例如)

另一个用途是语法糖。但是,在我以运行时开销为代价让代码看起来更干净之前,编译器知道如何优化这类东西吗?或者我应该只在潜在开销比不使用惰性评估更快的情况下使用它吗

下面是我的意思的一个例子。这不是我的实际用例,只是一个简单的非懒惰vs懒惰评估版本

// original
template < class out,
           class in >
out && lazy_cast( in && i )
{
    return ( out && )( i );
}

// usage
char c1 = 10;
int c2 = lazy_cast< int >( c1 );
//原件
模板
输出和延迟(输入和输入)
{
返回(输出和输出)(i);
}
//用法
字符c1=10;
int c2=延迟施法(c1);
//懒惰
模板
C类
{
公众:
在&i;
模板
运算符输出&()
{
返回(输出和输出)(i);
}
};
模板
C_lazy_castlazy_cast(in&&i)
{
返回{std::forward(i)};
}
//用法
字符c1=10;
int c2=延迟转换(c1);

为了完整起见,有关MSVC、GCC和clang的信息应该足够了。

编译器可以做的比您想象的多得多。 在你的例子中,我不确定你要做什么,但是考虑一下:

msvc
的输出可以说是三者中最不复杂的(因此最容易理解)

此外,如果您从编译时已知的输入值开始,这将内联到单个
returnnew_value
指令

请注意,在上面的示例中,编译器无法避免
if
条件,而“lazyCast”只是一个禁忌

是另一个有趣的例子,其中两个
if
语句和两个数学表达式被简单地取消

对于实际程序,实际效率很难/不可能从程序集预测-它取决于执行程序的机器,以及该机器所处的状态(例如,它是否同时运行不同的程序?)。即使这样,您也需要运行测试以确定哪一行工作得最好

当然,最好是主观的。您需要决定您是喜欢优化运行时间(可能会进一步细分)、可执行文件的大小还是电源需求


这需要大量的学习才能正确,但你可以放心,有一些非常有才华的人以解决这些问题为生,他们通常做得很好。

我不太明白你打算用
lazy\u cast做什么。你。。。传递一些参考资料?为什么不直接传递引用本身呢?@PasserBy它只是c风格铸造的包装。理论上,它应该会产生0行代码。但是为什么不直接传递引用呢?让强制转换不在使用点有什么意义?@路人通过传递引用,我们可以消除模板参数的需要,因为它们是在隐式转换过程中推导出来的。谢谢您的回答!这让我对编译器更有信心。你介意为其他编译器发布godbolt链接并在你的答案中讨论结果吗?@lajoh90686编辑了答案,并在第一个链接中编辑了代码。
// lazy
template < class in >
class C_lazy_cast
{
public:
    in && i;

    template < class out && >
    operator out &&( )
    {
        return ( out && )( i );
    }
};

template < class in >
C_lazy_cast< in > lazy_cast( in && i )
{
    return { std::forward< in >( i ) };
}

// usage
char c1 = 10;
int c2 = lazy_cast( c1 );
template <typename TLazyChar>
struct lazyUpperImpl{
    TLazyChar in;
    lazyUpperImpl(TLazyChar in_):in(in_){}
    char constexpr operator()(){
        auto c = in();
        if (c >= 'a' && c <= 'z'){
            c = c - 'a' + 'A';
        }
        return c;
    }
};

template <typename TLazyNumeric>
struct lazyAdd5Impl{
    TLazyNumeric in;
    lazyAdd5Impl(TLazyNumeric in_):in(in_){}
    int constexpr operator()(){
        return in() + 5;
    }
};

template <typename Tout, typename TLazyIn>
struct lazyCastImpl {
    TLazyIn in;
    lazyCastImpl(TLazyIn in_):in(in_){}

    Tout constexpr operator()(){
        return static_cast<Tout>(in());
    }
};

template <typename Tout, typename TLazyIn>
auto constexpr lazyCast(TLazyIn in){
    return lazyCastImpl<Tout, TLazyIn>(in);
}

template <typename TLazyChar>
auto constexpr lazyUpper(TLazyChar in){
    return lazyUpperImpl<TLazyChar>(in);
}

template <typename TLazyNumeric>
auto constexpr lazyAdd5(TLazyNumeric in){
    return lazyAdd5Impl<TLazyNumeric>(in);
}

int foo(int in){
    auto lazyInt = [in](){return in;};
    auto x =
        lazyAdd5(
            lazyCast<int>(
                lazyUpper(
                    lazyCast<char>(lazyInt)
                )
            )
        ) ();

    return x;
}

int main(){
    return foo(109);
}
    movzx   eax, cl
    cmp     cl, 97                      ; 00000061H
    jl      SHORT $LN26@foo
    cmp     cl, 122                     ; 0000007aH
    jg      SHORT $LN26@foo
    lea     eax, DWORD PTR [rcx-32]
$LN26@foo:
    movsx   eax, al
    add     eax, 5
    ret     0