如何根据模板参数有条件地声明局部变量?

use*_*251 7 c++ local-variables enable-if

我想根据模板 bool 参数有条件地在函数中声明局部变量。因此,如果这是真的,它应该在那里,否则不应该在那里,因为我不希望该变量在堆栈上分配内存或调用其构造函数。它也可以是基本类型。

我无法在 constexpr if 块中声明它,因为我需要用法之间的持久性。

  1. 我可以声明变量并添加[[maybe_unused]]. 那么,是否有编译器优化保证不为变量分配内存呢?

    template <bool T> void foo()
    {
        [[maybe_unused]] SomeLargeClass x;
        if constexpr(T)
        {
            /* ... do something with x */
        }
        /* ... do something without x */
        if constexpr(T)
        {
            /* ... do something more with x */
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我尝试将声明替换为

    std::enable_if_t<T, SomeLargeClass> x;
    
    Run Code Online (Sandbox Code Playgroud)

    但它不起作用,因为T==false案例无法提供类型。为什么这不是SFINAE?

  3. 我还有其他选择吗?

Jar*_*d42 6

As-if 规则可能会丢弃used SomeLargeClass,但如果该类进行分配,情况会更复杂。一个简单的权衡是在需要时使用std::conditional和拥有SomeLargeClass,在其他情况下使用一些虚拟的小类;

struct Dummy
{
    // To be compatible with possible constructor of SomeLargeClass
    template <typename ...Ts> Dummy(Ts&&...) {} 
};

template <bool B> void foo()
{
    [[maybe_unused]] std::conditional_t<B, SomeLargeClass, Dummy> x;
    if constexpr(B) {
        // ... do something with x
    }
    // ... do something without x
    if constexpr(B) {
        // ... do something more with x
    }
}
Run Code Online (Sandbox Code Playgroud)

作为替代方案,您可以重写您的函数,使您的类仅位于 constexpr 块中:

template <bool B> void foo()
{
    const auto do_something_without_x = [](){
        // ... do something without x
    };
    if constexpr(B) {
        SomeLargeClass x;
        // ... do something with x
        do_something_without_x();
        // ... do something more with x
    } else {
        do_something_without_x();
    }
}
Run Code Online (Sandbox Code Playgroud)


ana*_*lyg 0

如果您的类有一个简单的构造函数,请不用担心 - 编译器不会在堆栈上分配未使用的对象。

如果您的类有一个执行某些工作的构造函数,并且您知道它是浪费的,您可能希望跳过此工作。编译器可能仍然注意到该对象未被使用,并跳过构造函数。在对代码进行任何更改之前检查此项(过早优化)!

但如果构造函数有一些副作用(不推荐),则必须帮助编译器。一种方法是使用unique_ptr

template <bool T> void foo()
{
    unique_ptr<SomeLargeClass> x;
    if constexpr(T)
    {
        ... allocate x
        ... do something with *x
    }
    
    ... do something without x
    
    if constexpr(T)
    {
        ... do something more with *x
    }
}
Run Code Online (Sandbox Code Playgroud)