【问题标题】:C++ template recursion undefined typeC++模板递归未定义类型
【发布时间】:2021-05-02 10:40:11
【问题描述】:

我有用于添加、存储、跳转、返回和变量等指令的模板。然后我创建了 static_list 模板来存储这些指令。我想一一执行。我使用 enable_if_else 并比较成员指令来检查当前指令的类型并相应地分支。但是,如果它是变量类型指令,我在第一次检查后无法继续。 execute_v 和 execute_s 是这样工作的:

template<int index, class ...Commands>
struct execute_s <index, static_list<Commands ...>> {
    static constexpr int value = enable_if_else_v < static_list_get<index, static_list<Commands...>>::type::instruction == 1,
                                    1,
                                    0>::result ;
};

它返回 1 或 0,具体取决于我首先放入 execute_v 的指令类型。这可以正常工作。但是,当我想递归地继续执行下一个命令时,它不起作用,它看起来像这样:

template<int index, class ...Commands>
struct execute_s <index, static_list<Commands ...>> {
    static constexpr int value = enable_if_else_v < static_list_get<index, static_list<Commands...>>::type::instruction == 1,
                                    execute_s<index + 1, Commands...>::value,
                                    0>::result ;
};

问题在于execute_s&lt;index + 1, Commands...&gt;::value,因为当指令不是变量类型时它似乎不会停止,但我不知道为什么会这样,因为它应该停止。也许我错误地解压命令?我怎样才能实现我可以将所有命令的下一个索引推进到下一个递归级别? 这些是模板:

template<size_t VariableId, int InitValue>
struct variable {
    static constexpr size_t variableId = VariableId;
    static constexpr int value = InitValue;
    static constexpr int instruction = 1;
};

template<size_t DestinationVariableId, size_t SourceVariableId>
struct store {
    static constexpr size_t destinationVariableId = DestinationVariableId;
    static constexpr size_t sourceVariableId = SourceVariableId;
    static constexpr int instruction = 2;
};

template<size_t DestinationVariableId, size_t SourceVariableId>
struct add {
    static constexpr size_t destinationVariableId = DestinationVariableId;
    static constexpr size_t sourceVariableId = SourceVariableId;
    static constexpr int instruction = 3;
};

template<size_t VariableId, size_t CommandNumber>
struct jump_if_not_zero {
    static constexpr size_t variableId = VariableId;
    static constexpr size_t commandNumber = CommandNumber;
    static constexpr int instruction = 4;
};

template<size_t VariableId>
struct ret {
    static constexpr size_t variableId = VariableId;
    static constexpr int instruction = 5;
};

//-------------enable_if_else_v-------------
template<bool Cond, int TrueValue, int FalseValue>
struct enable_if_else_v;

template<int TrueValue, int FalseValue>
struct enable_if_else_v<true, TrueValue, FalseValue> {
    static constexpr int result = TrueValue;
};

template<int TrueValue, int FalseValue>
struct enable_if_else_v<false, TrueValue, FalseValue> {
    static constexpr int result = FalseValue;
};

//-------------static_list_get-------------
template<size_t Idx, class List>
struct static_list_get;

template<size_t Idx, class FirstElement, class ...Elements>
struct static_list_get<Idx, static_list<FirstElement, Elements ...>>
    : static_list_get<Idx - 1, static_list<Elements ...>> {
};

template<class FirstElement, class ...Elements>
struct static_list_get<1, static_list<FirstElement, Elements ...>> {
    using type = FirstElement;
};

//-------------execute_s-------------
template<int index, class ...Commands>
struct execute_s;

template<int index, class ...Commands>
struct execute_s <index, static_list<Commands ...>> {
    static constexpr int value = enable_if_else_v < static_list_get<index, static_list<Commands...>>::type::instruction == 1,
                                    execute_s<index + 1, Commands...>::value,
                                    0>::result ;
};

template<class ...Commands>
constexpr int execute_v = execute_s<1, static_list<Commands...>>::value;

这是主要功能示例:

int main() {
    constexpr size_t PREV = 0;
    constexpr size_t CURR = 1;
    constexpr size_t OLD_CURR = 2;
    constexpr size_t N = 3;
    constexpr size_t MINUS1 = 4;
    
    constexpr int fib_n = execute_v<
        variable<PREV, 0>,              // 1: PREV = 0
        variable<CURR, 1>,              // 2: CURR = 1
        variable<OLD_CURR, 0>,          // 3: OLD_CURR = 0
        variable<N, 10>,                // 4: N = 10
        variable<MINUS1, -1>,           // 5: MINUS1 = -1

        jump_if_not_zero<N, 8>,         // 6: if (N > 0) goto 8
        ret<PREV>,                      // 7: return 0

        store<OLD_CURR, CURR>,          // 8: OLD_CURR = CURR
        add<CURR, PREV>,                // 9: CURR += PREV
        store<PREV, OLD_CURR>,          // 10: PREV = OLD_CURR
        add<N, MINUS1>,                 // 11: N += -1
        jump_if_not_zero<N, 8>,         // 12: if (N > 0) goto 8
        ret<PREV>                       // 13: return PREV
    >;
    static_assert(fib_n == 55, "Wrong result");
}

编译错误: 使用未定义类型 'execute_s, variable, variable...(所有命令)..., ret>'

我尝试将命令打包成这样的列表:execute_s&lt;index + 1, static_list&lt;Commands...&gt;&gt;::value,但它不起作用,它不会停止递归。

【问题讨论】:

  • 我认为您的误解在于您认为以某种方式只评估了 enable_if_else 的一个分支,而实际上两者都是。这意味着没有什么可以阻止您的递归。您可能可以改用 SFINAE。
  • 如何评价他们两个?对于简单的例子,它有效。如何使用 SFINAE?
  • 即使只选择其中一个,也必须评估两者。
  • 我明白了,但我不知道如何使用 SFINAE,你能告诉我如何使用它吗?

标签: c++ variadic-templates


【解决方案1】:

您的示例有点不完整,但我会尝试为您提供 SFINAE 的总体思路。

template <bool condition, int index, typename list>
struct get_next_command_or_zero;

template <int index, typename list>
struct get_next_command_or_zero<false, index, list> {
    static constexpr int value = 0;
}

template <int index, typename... Commands>
struct get_next_command_or_zero<true, index, static_list<Commands...>> {
    static constexpr int value = execute_s<index + 1, Commands...>::value; // I think you example is wrong here since, execure_s is expecting a static_list?
}

在这里,我们首先使用 sfinae 来选择正确的偏特化,因此只有在选择了该路径时才会查找 execure_s&lt;...&gt;::value,否则会被丢弃和不求值。

现在在execute_s 你可以像这样使用它

static constexpr int value = get_next_command_or_zero<static_list_get<index, static_list<Commands...>>::type::instruction == 1, index, static_list<Commands...>>::value;

【讨论】:

  • 非常感谢!所以 SFINAE 只是将 execute_s 打包在另一个模板中,所以如果不需要它就不会执行?
  • 是的,首先进行条件评估和专业选择。下一个命令的评估只在一个专业化中完成,所以它被推迟到我们知道它是否需要之后。
  • 我也可以向您寻求有关 store 命令的帮助吗?如何获取 static_list 并通过给定的源 variableId 更改其中的一个变量值?我也尝试在那里使用 SFINAE,但它变得复杂了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 2021-07-10
  • 1970-01-01
  • 2011-02-17
相关资源
最近更新 更多