用于强制constexpr功能的constexpr-ness的惯用方法

时间:2018-05-24 21:32:29

标签: c++ c++11 c++14 c++17 constexpr

请考虑以下示例代码:

#include <tuple>
void blah();
int buh;

constexpr auto get() 
{ 
    return std::get<0>(std::make_tuple(&blah, &buh));
}

int main()
{
    get();
}

可以预期,因为函数get()是一个常量表达式,它将返回一个常量。

不是这样:std::make_tuplestd::get被实例化并被调用:https://godbolt.org/g/PkHrTp

现在,如果我们用

替换get()的实现
constexpr auto get() 
{ 
    constexpr auto x = std::get<0>(std::make_tuple(&blah, &buh));
    return x;
}

我们得到预期的行为:参数x的计算已经优化,即使在-O0,make_tupleget也没有实例化,这对于减少二元膨胀。

是否有一种惯用的方式来强制constexpr auto foo()形式的函数总是像第二个示例中那样?

现在我会诉诸:

#define constexpr_return(X) do { constexpr auto constexpr_return_x_ = X; return constexpr_return_x_; } while(0)

constexpr_return(std::get<0>(std::make_tuple(&blah, &buh)));
例如

但我不知道这是否是最佳的。

1 个答案:

答案 0 :(得分:2)

<Window x:Class="ObservableStackBug.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Button Content="Add" Margin="5" Padding="8 2" HorizontalAlignment="Left" Click="ButtonBase_OnClick"/>

        <ListBox ItemsSource="{Binding StateStack}" Grid.Row="1" />

        <TabControl Grid.Row="2" ItemsSource="{Binding Men}" SelectedIndex="{Binding DebugIndex}">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Index}" />
                </DataTemplate>
            </TabControl.ItemTemplate>
        </TabControl>
    </Grid>

</Window>

实际上必须在编译时评估非类型模板参数。

template<auto x> std::integral_constant< std::decay_t<decltype(x)>, x > k{}; 或在某些极端情况下k<get()>可能会执行您想要的操作。

对于不能作为非类型模板参数传递的k<get()>()值,这不起作用,但它适用于整数,指针和函数指针。