【问题标题】:How to match empty arguments pack in variadic template如何匹配可变参数模板中的空参数包
【发布时间】:2014-05-03 10:57:20
【问题描述】:

我有代码:

template<typename T>
void loadBrush_sub_impl()
{
    // do some work here
}

template<typename T, typename... Targs>
void loadBrush_sub()
{
    loadBrush_sub_impl<T>();
    loadBrush_sub<Targs...>();
}

template<>
void loadBrush_sub<void>()
{
}

// BasicBrush, BinaryBrush, SketchBrush, BasicEraser and MaskBased are class
loadBrush_sub<BasicBrush, BinaryBrush, SketchBrush, BasicEraser, MaskBased, void>();

编译时这是正确的。但是,我真的很想在电话loadBrush_sub&lt;BasicBrush, BinaryBrush, SketchBrush, BasicEraser, MaskBased, void&gt;(); 中删除void

但是,这会导致:

..\CanvasEngine\canvasengine.cpp: In instantiation of 'void loadBrush_sub() [with T = MaskBased; Targs = {}]':
..\CanvasEngine\canvasengine.cpp:36:5:   recursively required from 'void loadBrush_sub() [with T = BinaryBrush; Targs = {SketchBrush, BasicEraser, MaskBased}]'
..\CanvasEngine\canvasengine.cpp:36:5:   required from 'void loadBrush_sub() [with T = BasicBrush; Targs = {BinaryBrush, SketchBrush, BasicEraser, MaskBased}]'
..\CanvasEngine\canvasengine.cpp:114:81:   required from here
..\CanvasEngine\canvasengine.cpp:36:5: error: no matching function for call to 'loadBrush_sub()'
..\CanvasEngine\canvasengine.cpp:36:5: note: candidate is:
..\CanvasEngine\canvasengine.cpp:33:6: note: template<class T, class ... Targs> void loadBrush_sub()
..\CanvasEngine\canvasengine.cpp:33:6: note:   template argument deduction/substitution failed:
..\CanvasEngine\canvasengine.cpp:36:5: note:   couldn't deduce template parameter 'T'
mingw32-make[1]: *** [release/canvasengine.o] Error 1

我用enable_if 进行了一些实验,但没有运气。

是否有任何解决方案可以删除 void 并使编译器满意?

【问题讨论】:

  • 为什么不删除template&lt;&gt; void loadBrush_sub&lt;void&gt;() 专业化?
  • @Constructor 我认为这并不重要。编译器无法推断出空包,无论有没有这种特化。
  • 试试去掉看看效果。
  • @Constructor 结果相同。我在这些类后面写了专业化和void,因为它有那个错误。删除它只会让我回到原来的状态。

标签: c++ templates variadic-templates variadic-functions


【解决方案1】:

最简单的解决方案是添加另一个间接:

template<typename T>
void loadBrush_sub_impl()
{
    // do some work here
}

template<typename... Targs>
void loadBrush_sub();

template<typename T, typename... V>
void loadBrush_sub_helper()
{
    loadBrush_sub_impl<T>();
    loadBrush_sub<V...>();
}

template<typename... Targs>
void loadBrush_sub()
{
    loadBrush_sub_helper<Targs...>();
}

template<>
void loadBrush_sub<>()
{
}

【讨论】:

  • 因为它不是函数模板的(禁止)部分特化,而是完全特化。
  • @DieterLücking 在答案中给出了另一个明显的解决方案,他使用了类的部分特化(这是允许的)。
【解决方案2】:

没有助手(注意“= void”):

template<typename T>
void loadBrush_sub_impl()
{
    // do some work here
}

template<typename T = void, typename... Targs>
void loadBrush_sub();

template<typename T, typename... Targs>
void loadBrush_sub()
{
    loadBrush_sub_impl<T>();
    loadBrush_sub<Targs...>();
}

template<>
void loadBrush_sub<>()
{
}

【讨论】:

    【解决方案3】:

    你可以专门化一个辅助结构:

    #include <iostream>
    
    namespace Detail {
        template<typename T, typename... Targs>
        struct LoadBrush;
    
        template<typename T>
        struct LoadBrush<T> {
            static void sub() {
                std::cout << "Work\n";
            }
        };
    
        template<typename T, typename... Targs>
        struct LoadBrush {
            static void sub() {
                LoadBrush<T>::sub();
                LoadBrush<Targs...>::sub();
            }
        };
    }
    
    template<typename... Targs>
    void loadBrush_sub()
    {
        Detail::LoadBrush<Targs...>::sub();
    }
    
    
    struct BasicBrush {};
    struct BinaryBrush {};
    struct SketchBrush {};
    struct BasicEraser {};
    struct MaskBased {};
    
    int main()
    {
        loadBrush_sub<BasicBrush, BinaryBrush, SketchBrush, BasicEraser, MaskBased>();
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      另一种方法是使用 SFINAE。

      #include <type_traits>
      template<typename T>
      void loadBrush_sub_impl()
      {
          // do some work here
      }
      
      template<typename T>
      void loadBrush_sub()
      {
          loadBrush_sub_impl<T>();
      }
      
      template<typename T, typename... Ts>
      std::enable_if_t<(sizeof...(Ts) > 0), void> 
      loadBrush_sub()
      {
          loadBrush_sub_impl<T>();
          loadBrush_sub<Ts...>();
      }
      

      【讨论】:

        猜你喜欢
        • 2023-03-07
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 2015-12-06
        • 2012-08-08
        • 2016-12-01
        相关资源
        最近更新 更多