constexpr函数中的编译时类型生成

时间:2017-09-01 14:34:18

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

import pandas as pd
from io import StringIO
csv_data = '''A,B,C,D
1.0, 2.0, 3.0, 4.0
5.0, 6.0, 7.0, 8.0
9.0, 10.0, 11.0, 12.0'''
df = pd.read_csv(StringIO(csv_data))
df.transpose()

使用 - std = c ++ 17 gcc-7.2 无法编译代码出现以下编译错误:

#include <array>
#include <tuple>

typedef std::tuple<const int> TupleType;

constexpr std::array<const int, 2> a = {1, 2};

constexpr void foo()
{
    for (std::size_t i = 0; i < a.size(); ++i)
    {
        const int j = i;
        typedef std::tuple_element<j, TupleType> T;
    }
}

如果我们假设在编译时评估函数(和相应的循环)(这对于从 c ++ 14 开始的循环是可行的),为什么这个代码不能被编译为即使 i 未声明为 const ,它实际上也可以是 constexpr ,因为它的所有值在编译时都是已知的好。

请您澄清这个代码是否因其想法无效?或者有编译器限制?或者以下都没有?

3 个答案:

答案 0 :(得分:2)

  

请您澄清这个代码是否因其想法无效?

它是 - 您正在尝试将可变且有状态的迭代变量用作常量表达式常量表达式的整个概念围绕着不变性。在编译期间是否执行循环无关紧要。

您实际应该做的是为以下代码段生成代码

{
    typedef std::tuple_element<j, TupleType> T;
    // ...
}

j常量表达式的占位符。这是一种可行的方法:

template <typename F, typename... Ts>
constexpr void for_each_arg(F&& f, Ts&&... xs)
{
    (f(std::forward<Ts>(xs)), ...);
}

constexpr void foo()
{
    for_each_arg([](auto c)
    {
        typedef std::tuple_element<c, TupleType> T;
    },
    std::integral_constant<int, 1>{}, 
    std::integral_constant<int, 2>{});
}

live example on wandbox

请注意,for_each_arg上的更高级抽象可以轻松提供(例如,在编译时数字范围内迭代,或将constexpr数组转换为{{1}的序列而代之以迭代)

答案 1 :(得分:1)

编译器是对的。 ij而不是constexpr。找你自己:

//    v--- not constexpr
for (std::size_t i = 0; i < a.size(); ++i)
    {
        // Not constexpr either
        const int j = i;
        typedef std::tuple_element<j, TupleType> T;
    }

如果您尝试标记j constexpr,您会发现,因为i不是,所以不能如此。

如果您尝试声明i constexpr,您将看到constexpr变量与任何constexpr变量的规则相同:您不能改变它们。

那么如何循环数字来生成类型呢?

您可以将包扩展与索引序列一起使用:

template<typename T, T... S, typename F>
void for_sequence(std::integer_sequence<S...>, F f)
{
    using unpack = int[];
    (void) unpack{(f(std::integral_constant<T, S>{}), void(), 0)..., 0};
}

constexpr void foo()
{
    for_sequence(std::make_index_sequence<a.size()>{}, [](auto i)
    {
        typedef std::tuple_element<i, TupleType> T;
    });
}

答案 2 :(得分:0)

每个openModal(){ $('#myModal').modal('show'); } 函数必须能够在运行时进行评估。

constexpr并不意味着“必须在编译时运行”,这意味着“可能在编译时运行”。

没有基本原因可以解释为什么在每次迭代时都没有constexpr循环使索引成为constexpr for值。但是C ++没有那个。

它确实有一个constexpr,它与你想要的精神相似。

直到它成功,你必须自己编写。

constexpr if

是C ++ 17中未编译的示例(大多数是17,因为它有constexpr lambdas)。