繁体   English   中英

在可变参数 function 模板中,可以从模板参数包元素中推断出返回类型

[英]In a variadic function template can the return type be deduced from the template parameter pack elements

我正在尝试编写可变参数 function 模板。 function 的第一个参数是 integer 索引值。 (变数)arguments的rest代表变数arguments。 此 function 必须返回位置索引处的参数。 例如,如果 function 被调用为

`find_item(1, -1, "hello", 'Z', 10.03)`

它必须返回"hello"

如果调用为

find_item(2, -1, "hello", 'Z', 10.03)

它必须返回'Z'

如果调用为

find_item(3, -1, "hello", 'Z', 10.03, 'Q', 100)

它必须返回10.03等....

我正在尝试以下代码:

template <class T>
auto find_item(int inx, T val) { return val ;}

// GENERAL CASE
template <class T, class... Others>
auto find_item(int inx, T a1, Others ... others) {
    if(inx==0) return a1 ;
    else return print(inx-1, others...) ;
}

int main() {
    cout<<find_item(1, -1, "hello", string("abvd"), 10.03)<<endl ; ;
}

此代码无法编译,因为返回类型不统一,无法推断。 我想知道是否有任何方法可以实现这一点。 或者它是一个无效的用例。 如果这可以实现,那么如何实现。

这不是 C++ 处理它的惯用方式,但您可以 model 使用 std::variant 返回不同的类型。 variant_cast是将variant<T...>转换为variant<S...>的助手,其中 S 是 T 的超集。

#include <variant>
#include <iostream>

template <class... Args>
struct variant_cast_proxy
{
    std::variant<Args...> v;

    template <class... ToArgs>
    operator std::variant<ToArgs...>() const
    {
        return std::visit([](auto&& arg) -> std::variant<ToArgs...> { return arg ; },
                          v);
    }
};

template <class... Args>
auto variant_cast(const std::variant<Args...>& v) -> variant_cast_proxy<Args...>
{
    return {v};
}


template <class T>
std::variant<T> find_item(int inx, T val) { return val ;}

// GENERAL CASE
template <class T, class... Others>
std::variant<T, Others...> find_item(int inx, T a1, Others ... others) {
    if(inx==0) return a1 ;
    else return variant_cast(find_item<Others...>(inx-1, others...)) ;
}



int main() {
    std::visit([](auto v){std::cout << v << std::endl;}, 
               find_item(1, -1, "hello", std::string("abvd"), 10.03)) ;
}

由于您的返回类型由运行时变量inx确定,因此无法在编译时知道find_item的确切返回类型。

您需要做的是类型擦除。 您可以返回std::variant<Args...>并根据 inx 的值使用相应的inx构造它。 例如:

#include <variant>
#include <array>
#include <tuple>

template<class... Args>
constexpr auto find_item(std::size_t index, Args... args) {
  constexpr auto indices = []<std::size_t... Is>(std::index_sequence<Is...>) {
    using var_t = std::variant<std::integral_constant<std::size_t, Is>...>;
    return std::array{var_t{std::in_place_index<Is>}...};
  }(std::index_sequence_for<Args...>{});

  return std::visit([&...args = args](auto i) {
    return std::variant<Args...>{
      std::in_place_index<i>,
      std::get<i>(std::tuple(args...))};
  }, indices[index]);
}

演示

我想知道是否有任何方法可以实现这一点。

不。

在 C/C++(静态类型语言)中,从 function 返回的类型必须取决于 arguments 的类型,而不是值。

所以从以下调用返回的类型

find_item(1, -1, "hello", 'Z', 10.03);
find_item(2, -1, "hello", 'Z', 10.03);
find_item(3, -1, "hello", 'Z', 10.03);

必须相同。

观点。

您可以绕过此规则,返回std::variant (可以包含不同类型的值)或std::any (可以包含泛型值),但类型是独立于接收到的值确定的。

如果您将所需的类型/值的索引(在您的情况下为第一个参数)作为模板参数传递,则不同。

我的意思是:如果您按如下方式调用find_item()则不同

find_item<1>(-1, "hello", 'Z', 10.03);
find_item<2>(-1, "hello", 'Z', 10.03);
find_item<3>(-1, "hello", 'Z', 10.03);

现在find_item<1>()可以返回一个char const *find_item<2>()可以返回一个char并且find_item<3>()可以返回一个double

这是因为find_item<1>()find_item<2>()find_item<3>()是不同的函数,所以可以有不同的返回类型。

但是......这样......我们几乎已经获得了从std::tuple中提取值的std::get<>()

不幸的是,只有当索引(模板参数)是已知的编译时间时,您才能使用此解决方案。

换句话说,你不能做如下的事情

for ( auto i = 1 ; i < 4 ; ++i )
 { // .............NO! ---V
   auto value = find_item<i>(-1, "hello", 'Z', 10.03);
 }
   

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM