代码之家  ›  专栏  ›  技术社区  ›  BiagioF

空包变量模板

  •  2
  • BiagioF  · 技术社区  · 6 年前

    假设我在编译时要执行一些操作:

    enum class Action {A, B};
    

    现在我编写了一个模板变量函数,它按顺序执行可能的操作组合:

    template <Action a>
    void applyAction();
    
    template <typename = void>
    void applyActions() {}
    
    template <Action a, Action... as>
    void applyActions() {
      applyAction<a>();
      applyActions<as...>();
    }
    

    这个代码很好。的确:

    void foo() {
      applyActions<Action::A, Action::B>();
    }
    

    正确生成:

    call void applyAction<(Action)0>()
    call void applyAction<(Action)1>()
    

    GodBolt Example Here


    为了实现扩展包终止,我必须声明虚拟函数:

    template <typename = void> void applyActions() {}
    

    这对我来说相当“难看”,因为它提供了调用泛型类型的可能性。

    在C++ 11中 ,是否有方法声明接受空参数包的变量函数?

    当然, 它的声明不必使用所需的函数引起调用的歧义:

    template <Action a, Action... as>
    void applyActions();
    

    比如:

    template <Action.. = {}>
    void applyActions() {}
    

    Here 由于调用不明确而无法编译的示例。但它给出了我想要达到的目标。

    2 回复  |  直到 6 年前
        1
  •  5
  •   rmawatson    6 年前

    另一种构造它的方法是删除“丑陋的”默认值,这也删除了递归,并且可以使用空的actions参数包。

    #include <iostream>
    using namespace std;
    
    enum class Action {A, B};
    
    template <Action a>
    void applyAction()
    {
       std::cout << "Action  " << (int)a << std::endl;
    }
    
    template <Action... as>
    void applyActions() {
        using do_= int[];
        (void)do_{0, ( 
           applyAction<as>()
        ,0)...}; 
    }
    
    void foo() {
      applyActions<Action::A, Action::B>();
    }
    
    void bar() {
      applyActions<Action::B, Action::A>();
    }
    
    
    int main() {
        foo();
        bar();
        return 0;
    }
    

    Demo

    正如HolyBlackCat所指出的,在C++ 17中,可以使用折叠表达式,

    template <Action... as>
    void applyActions() {
    
           (applyAction<as>(), ...);
    }
    
        2
  •  1
  •   max66    6 年前

    在C++ 11中,是否有一种方法来声明一个接受空参数包的变量函数?

    有,而且很小

    template <Action...>
    void applyActions()
    

    问题是,在您的例子中,与接受一个或多个元素的函数冲突

    template <Action a, Action... as>
    void applyActions()
    

    当你打电话的时候 applyActions<as...>(); 有一个不空的 as... 包装,两个模板匹配。

    使用具有相同名称但不同类型参数(和默认值)的模板函数

    template <typename = void>
    void applyActions() {}
    

    这是一个非常聪明,廉价和优雅的方式来解决终止问题。