如何简化模板化回调函数的定义?

时间:2016-04-28 10:21:48

标签: c++ templates callback

我编写了一个模板化的Matrix结构,它通过使用地图在内部抽象连续索引。

Matrix<TCell, TKey> m;

有一个扩展结构的功能,我想让用户能够传递一个填充新创建的单元格的函数指针(initFunc)。

   void ExpandMatrix( Matrix<TCell, TKey>* matrix, 
                      std::set<TKey>* keys_c, 
                      std::set<TKey>* keys_r, 
                      ??? /*Function pointer to callback function */ 
                     )

现在我的问题是,这个用户提供的函数需要传递一个指针和单元格的键,而不是我使用的任何内部计数器。并且这些通过模板定义为TCellTKey。所以我不能使用它,因为还不知道究竟TCellTKey是什么:

typedef void (*initFunc)(TCell* pCell, TKey key_c, TKey key_r)

就我的研究而言,无法模拟函数指针:

template<typename TCell, typename TKey> 
typedef void (*initFunc)(TCell* pCell, TKey key_c, TKey key_r)

我目前所做的是将函数包装在用户被认为派生的类中,但这对用户来说很麻烦。难道没有更好的解决方案吗?

template <typename TCell, typename TKey>
class DefaultCellInitializer
{
    public:
    virtual void Initialize(TCell* t, TKey key_c, TKey key_r)
    {
        return;
    }
};

template<typename TCell, typename TKey>
void ExpandMatrix(  Matrix<TCell, TKey>* matrix, 
                    std::set<TKey>* keys_c, 
                    std::set<TKey>* keys_r, 
                    CellInitializer<TCell, TKey> initializer = DefaultCellInitializer)

注意:我需要允许一个默认值,它无法应对该方法的传统用法。 C ++ 11是受欢迎的,但它必须在MSVC 2012上编译。由于政治原因,Boost不是一个选项。

2 个答案:

答案 0 :(得分:3)

您不需要typedef模板函数指针。您可以直接将ExpandMatrix()的参数类型定义为函数指针:

template<typename TCell, typename TKey>
void ExpandMatrix(Matrix<TCell, TKey>* matrix, 
                  void (*initFunc)(TCell*, TKey, TKey) = defaultCellInitializer) {}

defaultCellInitializer()可能是

template<typename TCell, typename TKey>
void defaultCellInitializer(TCell* pCell, TKey key_c, TKey key_r) {
    ... ...
}

LIVE

答案 1 :(得分:2)

您可以使用std::function使用这些模板类型。这可以绑定到lambda。

template <typename TCell, typename TKey>
void ExpandMatrix( Matrix<TCell, TKey>* matrix, 
                  std::set<TKey>* keys_c, 
                  std::set<TKey>* keys_r, 
                  std::function<void(TCell*, TKey, TKey)> callback
                 );

然后是lambda:

ExpandMatrix(/* args */, []( /* type list for arguments */ ) {
  /* implementation */
  });

将lambda绑定到std::function时,您需要在所需参数列表中提供类型。

如果您不限于lambda,也可以使用函数指针。

此外,std::function可以用自己的模板参数替换,并以与标准库在其算法中使用谓词等相同的方式使用(例如std::find_if);

template <typename TCell, typename TKey, typename Callback>
void ExpandMatrix( Matrix<TCell, TKey>* matrix, 
                  std::set<TKey>* keys_c, 
                  std::set<TKey>* keys_r, 
                  Callback callback
                 );

同样,callback可以绑定到函数指针,仿函数,lambda等。