c++ - 范围内的模板变量或模板 typedef

标签 c++ templates c++17

为什么不能在范围内声明模板变量或模板 typedef?

我想像这样用c++17写一段代码

auto foo = [](auto fun, auto... x) {
  template <typename T>
  using ReturnType = std::invoke_result_t<fun, T>;

  if constexpr (!(std::is_same_v<void, ReturnType<decltype(x)>> || ... ||
                  false)) {
    return std::tuple<ReturnType<decltype(x)>...>(fun(x)...);
  } else {
    (fun(x), ...);
    return;
  }
};

这段代码定义了一个函数foo它需要一个函数 fun和一堆论点x... .如果所有返回类型 fun(x)不是 void然后返回一个结果元组。如果至少一种返回类型是 void然后调用所有函数但返回 void .

在这个简单的例子中,我当然可以替换 ReturnType<decltype(x)>decltype(fun(x)) ,但在我的用例中,实际类型要复杂得多,上面的代码仅作为动机。

另外,我讨厌写作 ReturnType<decltype(x)> .我更喜欢写 ReturnType(x) ,但这可能是不可能的。


我不喜欢的解决方案: 在函数外定义模板 typedef 为

template<typename Fun, typename T>
using ReturnType = std::invoke_result_t<Fun,T>;

然后在函数中使用

ReturnType<decltype(fun),delctype(x)>

时间越来越长,我必须将每个本地类型都作为模板参数。

最佳答案

代码实际上更简单,没有引入任何助手:

if constexpr ((!std::is_void_v<decltype(fun(x))> && ...)) {
    return std::tuple(fun(x)...);
} else {
    (fun(x), ...);
}

&&||具有空包的默认值(分别为 truefalse),因此您不必将它们转换为一元运算符。而且你不需要 invoke_result_t因为你只是直接打电话。即使你这样做了:

using F = decltype(fun);
if constexpr ((!std::is_void_v<std::invoke_result_t<F, decltype(x))> && ...)) {
    return std::tuple(std::invoke(fun, x)...);
} else {
    (fun(x), ...);
}

不久。


也就是说,我发现这个构造不是很有用 - 考虑到您对 void 得到的结果截然不同和非 void个案。也许f(x)仍然是 X但是f(y)void ,我们会得到 foo(x,x)正在tuple<X,X>但是foo(x,y)正在void ?很难编码。

我建议不要删除所有返回类型,而是解决损坏的类型。如:

struct Void { };

template <typename F, typename... Args,
    typename R = std::invoke_result_t<F, Args...>,
    REQUIRES(std::is_void_v<R>)>
Void invoke_void(F&& f, Args&&... args) {
    std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
    return Void{};
}

template <typename F, typename... Args,
    typename R = std::invoke_result_t<F, Args...>,
    REQUIRES(!std::is_void_v<R>)>
R invoke_void(F&& f, Args&&... args) {
    return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}

现在,我们可以随时调用函数并返回它:

auto foo = [](auto fun, auto... x) {
    return std::tuple(invoke_void(fun, x)...);
};

关于c++ - 范围内的模板变量或模板 typedef,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49214517/

相关文章:

c++ - OpenCV 轮廓时刻?

C++ 编译时类型检查

c++ - 初始化嵌套模板类

c++ - 为什么 std::get for variant 会引发失败而不是未定义的行为?

c++ - nullptr、{} 和 nullopt 之间的区别

c++ - C++17 中 std::unordered_map 的推导指南

c++ - 通过 uva 的中值程序

具有 GSL、LAPACK 或 CBLAS 等数学库的 C++ 性能与具有 R 函数的 Rinside 的 C++ 相比?

c++ - 模板类中的静态成员初始化

c++ - 在 Matlab 中包装 C++ 代码以访问 Matlab 中的程序状态信息