如果作为参数传递的函子不带参数,则启用模板

时间:2019-08-14 15:33:22

标签: c++ templates overloading variadic-templates sfinae

我正在尝试为模板函数定义两个重载。 如果作为参数传递的函子没有参数,则会生成第一个重载,否则会生成第二个重载。 我开始像这样实现:

template <typename R, typename... Types>
constexpr size_t argumentCount(R (*f)(Types...))
{
    return sizeof...(Types);
}

template <typename Function>
typename std::enable_if<argumentCount<Function>() == 0, int>::value = 0 > callFunc(Function fu)
{
    fu();
}

template <typename Function, typename... Params>
typename std::enable_if<argumentCount<Function>() == 0, int>::value = 0 > callFunc(Function fu, Params... params)
{
    fu(std::forward<decltype(params)>(params)...);
}

由于包括解析错误在内的多种原因,它无法编译。我想做的是

callFunc([](){});将调用重载1,而callFunc([](int value1,int value2){});将调用重载2。

我该如何实现?

4 个答案:

答案 0 :(得分:3)

您可以将检测惯用法与std::void_tstd::declval结合使用来检测此类特征。

template <typename FuncT>
using invocable_without_args_t = std::void_t<decltype(std::declval<FuncT>()())>;

更多信息为available here;这篇文章对我的理解很有帮助。

答案 1 :(得分:1)

  1. 以下是您使用固定语法的版本:
template <typename R, typename... Types>
constexpr size_t argumentCount(R (*f)(Types...))
{
    return sizeof...(Types);
}

template <typename Function>
typename std::enable_if<argumentCount<Function>() == 0, int> callFunc(Function fu)
{
    fu();
}

template <typename Function, typename... Params>
typename std::enable_if<argumentCount<Function>() == 0, int> callFunc(Function fu, Params... params)
{
    fu(std::forward<decltype(params)>(params)...);
}
  1. 在此特定示例中,您不需要额外的重载,Types...可以为空。
    template <typename Function, typename... Params>
    auto callFunc(Function fu, Params... params)
    {
        fu(std::forward<decltype(params)>(params)...);
    }

效果很好。

答案 2 :(得分:1)

如果您可以添加一个间接级别...使用标记分派代替SFINAE怎么办?

我的意思是,如下

#include <iostream>
#include <type_traits>

template <typename F>
void callFunc_helper (F fu, std::true_type)
 {
   std::cout << "zero version" << std::endl;

   fu();
 }

template <typename F, typename... Prs>
void callFunc_helper (F fu, std::false_type, Prs && ... params)
 {
   std::cout << "non zero version" << std::endl;

   fu(std::forward<Prs>(params)...);
 }

template <typename F, typename... Prs>
void callFunc (F fu, Prs && ... params)
 { callFunc_helper(fu, std::integral_constant<bool, 0u == sizeof...(Prs)>{},
                   std::forward<Prs>(params)...); }

int main ()
 {
   callFunc([]{});
   callFunc([](int, int){}, 0, 1);
 }

很明显,如果您确实要检查功能参数的数目而不是以下参数的数目,可以使用std::integral_constant<bool, 0u == argumentCount<Function>()>{}

答案 3 :(得分:0)

如果需要两个模板函数,只需编写它们:

#include <iostream>

template <class R>
void callFunc(R (*f)()) {
    std::cout << "Called no-arg template\n";
    f();
}

template <class R, class T, class... Types, class... Params>
void callFunc(R (*f)(T, Types...), Params... params) {
    std::cout << "Called multi-arg template\n";
    f(params...);
}

void g() {
    std::cout << "Called g\n";
}

void h(int) {
    std::cout << "Called h\n";
}

int main() {
    callFunc(g);
    callFunc(h, 3);
    return 0;
}

输出:

[temp]$ clang++ -std=c++11 test.cpp
[temp]$ ./a.out
Called no-arg template
Called g
Called multi-arg template
Called h
[temp]$