如何在编译时通过名称/指针获取模板参数默认值的函数类型?

alv*_*eko 1 c++ templates c++11

有没有办法在编译时通过名称/指针获取一个函数类型,并将其用作模板参数的默认值?

请考虑以下代码:

template <typename TreeNode>
void default_visitor(TreeNode* node)
{
    std::cout << node->data << std::endl;
}

template <typename TreeNode, typename Visitor>
void binary_tree_traverse(TreeNode* root, Visitor visitor)
{
    /* some tree traversal calling the visitor for a node: */
    visitor(root);
}
Run Code Online (Sandbox Code Playgroud)

之后,binary_tree_traverse()可以使用任何访问者类型调用,例如:

// call with lambda
binary_tree_traverse(root,
                     [](BinaryTreeNode *node)
                     { std::cout << node->data << std::endl; });

// call with default_visitor() or anything else...
binary_tree_traverse(root, default_visitor<BinaryTreeNode>);
Run Code Online (Sandbox Code Playgroud)

但是,我希望能够省略visitor参数并像这样调用函数:

binary_tree_traverse(root);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它应该表现得就像调用它一样default_visitor<>.

问题是如何更改模板功能定义?像下面这样的东西将是一个理想的解决方案:

template <typename TreeNode,
          typename Visitor = ?typeof? default_visitor<TreeNode>>
void binary_tree_traverse(TreeNode* root,
                          Visitor visitor = default_visitor<TreeNode>)
{
    visitor(root);
}
Run Code Online (Sandbox Code Playgroud)

知道怎么做吗?它甚至可能吗?

另一种解决方案可能是使用模板特化(或者这个名称是什么?)并定义一个额外版本的函数(在这种情况下可以删除第二个函数参数,但想法是一样的):

template<typename TreeNode>
using typeof_default_visitor = void(*)(TreeNode*);

template <typename TreeNode>
void binary_tree_traverse(TreeNode* root,
                          typeof_default_visitor<TreeNode> visitor = default_visitor<TreeNode>)
{
    // call the generic version:
    binary_tree_traverse<TreeNode, typeof_default_visitor<TreeNode>>(root, visitor);
}
Run Code Online (Sandbox Code Playgroud)

但这看起来不太好,是吗?为了默认参数,额外的[dummy]函数似乎有点矫枉过正.什么是正确的(真正的C++)方法来解决这个问题?这里有什么选择?

Cat*_*lus 5

重载,但没有第二个参数而不是默认参数.不,它不是〜矫枉过正〜,这是最简单的解决方案.

template <typename Node, typename Fn>
void foo(Node* root, Fn&& func) {
    // ...
}

template <typename Node>
void foo(Node* root) {
    foo(root, some_default_func);
}
Run Code Online (Sandbox Code Playgroud)

  • @alveko少冗余.可能更容易理解.(你也是从错误的方式接近这个 - 通过KISS更简单更好,所以你应该问这个decltype的好处) (2认同)