有没有一种方法可以部分基于lambda参数返回类型来专门化我的模板化函数?

时间:2018-08-10 02:47:23

标签: c++ templates

我已经编写了一个模板化函数,旨在接受lambda和一堆参数。我已将函数的返回类型声明为lambda的返回类型。有什么方法可以让我的模板化函数专门用于某些lambda参数返回类型?

我的代码的工作部分如下:

template <typename F, typename ... T>
auto crudeProfile(F f, T ... args) -> decltype(f(args...)) {...}

这就像我期望的那样工作。但我想将其行为专门针对返回无效值的lambda。到目前为止,我只想出了以下代码:

template <typename F, typename ... T>
void crudeProfile(F f, T ... args) {...}

但是当我尝试使用它时,编译器会抱怨这一点:

1>Source.cpp(684): error C2668: 'crudeProfile': ambiguous call to overloaded function
1>  Source.cpp(637): note: could be 'void crudeProfile<main::<lambda_a7118596c99e3162db30942634c4e81e>,>(F)'
1>          with
1>          [
1>              F=main::<lambda_a7118596c99e3162db30942634c4e81e>
1>          ]
1>  Source.cpp(624): note: or       'void crudeProfile<main::<lambda_a7118596c99e3162db30942634c4e81e>,>(F)'
1>          with
1>          [
1>              F=main::<lambda_a7118596c99e3162db30942634c4e81e>
1>          ]
1>  Source.cpp(684): note: while trying to match the argument list '(main::<lambda_a7118596c99e3162db30942634c4e81e>)'

即使返回非空的lambda也会导致此错误,尽管该错误会稍有变化,显示为“可能是'type'或void”(其中'type'是lambda返回类型是什么)。

2 个答案:

答案 0 :(得分:1)

  

有没有办法专门化我的模板化函数?

不,您不能,但是有一种解决方法。

  

对我来说升级到C ++ 17可能不会受伤...

因此在C ++ 17中,多亏了if constexpr,您可以为此编写一个非常简单的解决方法,而又不会过多地损害您的代码,如下所示:

template <typename F, typename ... Ts>
decltype(auto) crudeProfile(F f, Ts ... args)
{
    if constexpr (std::is_same_v<std::invoke_result_t<F, Ts...>, void>)
    {
        // void
    }
    else
    {
        // not void
    }
}

答案 1 :(得分:0)

您不能部分专门化函数模板,并且重载也是不可能的事情 1 ,所以您必须诉诸于类。请注意,如果可以访问C ++ 17,则可以使用if constexpr来简化很多操作。

template <typename F, typename = void, typename... Ts>
struct helper {
    auto operator()(F f, Ts... args) -> decltype(f(args...)) {
      // your code
    }
};

template <typename F, typename... Ts>
struct helper<F, typename std::result_of<F(Ts...)>::type, Ts...> {
    void operator()(F f, Ts... args) {
        // specialization for void
    }
};

template <typename F, typename... Ts>
auto crudeProfile(F f, Ts... args) -> decltype(f(args...)) {
    return helper<F, Ts...>(f, args...);
}

注意:std::result_ofstd::invoke_result取代,因此,如果您可以改用(C ++ 17),请改用它。


1 请注意,您仍然可以使用SFINAE,但是我不喜欢此选项,因为这将需要您复制一个二进制条件(即,调用f(args...)的结果是一个空白)。

如果要这样做而不是通过帮助程序,只需在两个重载中添加一个附加模板参数即可:typename std::enable_if<!std::is_same<void, typename std::result_of<F(Ts...)>::type>::value>::type* = nullptr>。不要忘记删除第二个过载的否定项。