在可变参数函数模板中,可以从模板参数包元素中推导出 return 类型
In a variadic function template can the return type be deduced from the template parameter pack elements
我正在尝试编写可变函数模板。
该函数的第一个参数是一个整数索引值。
其余(可变数量的)参数代表可变数量的参数。
此函数必须 return 位置索引处的参数。
例如,如果函数被调用为
`find_item(1, -1, "hello", 'Z', 10.03)`
必须return"hello"
如果调用为
find_item(2, -1, "hello", 'Z', 10.03)
必须return'Z'
如果调用为
find_item(3, -1, "hello", 'Z', 10.03, 'Q', 100)
它必须 return 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 ; ;
}
这段代码编译不通过,因为return类型不统一,无法推导。
我想知道是否有任何方法可以实现这一目标。或者它是一个无效的用例。
如果能做到,那怎么做。
这不是 C++ 惯用的处理方式,但您可以使用 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)) ;
}
由于您的 return 类型由 运行 时间变量 inx
决定,因此无法知道 find_item
的确切 return 类型在编译时。
你需要做的是键入擦除。可以returnstd::variant<Args...>
,根据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]);
}
另一种类型擦除的方法是使用函数指针:
#include <variant>
#include <array>
#include <tuple>
template<class... Args>
constexpr auto find_item(std::size_t index, Args... args) {
constexpr auto funcs = []<std::size_t... Is>(std::index_sequence<Is...>) {
return std::array{ +[](Args... args) {
return std::variant<Args...>(
std::in_place_index<Is>, std::get<Is>(std::tuple(args...)));
}... };
}(std::index_sequence_for<Args...>{});
return funcs[index](args...);
}
I want to know if there is any way that this can be achieved.
没有
在 C/C++(静态类型语言)中,从函数 编辑的类型 return 必须 取决于 参数的类型,而不是值。
所以类型 return 来自以下调用
find_item(1, -1, "hello", 'Z', 10.03);
find_item(2, -1, "hello", 'Z', 10.03);
find_item(3, -1, "hello", 'Z', 10.03);
必须相同。
点。
您可以绕过此规则 return使用 std::variant
(可以包含不同类型的值)或 std::any
(可以包含通用值),但是独立于接收值确定的类型。
如果您将 type/value 的索引(在您的情况下是第一个参数)作为模板参数传递,则不同。
我的意思是:如果你按如下方式调用 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>()
可以return一个char const *
,find_item<2>()
可以return一个char
和find_item<3>()
可以return一个double
.
这是因为find_item<1>()
、find_item<2>()
和find_item<3>()
是不同的函数,所以可以有不同的return类型。
但是...这样...我们几乎获得了从 std::tuple
.
中提取值的 std::get<>()
不幸的是,只有当索引(模板参数)在编译时已知时,您才能使用此解决方案。
换句话说,你不能做出如下的东西
for ( auto i = 1 ; i < 4 ; ++i )
{ // .............NO! ---V
auto value = find_item<i>(-1, "hello", 'Z', 10.03);
}
我正在尝试编写可变函数模板。 该函数的第一个参数是一个整数索引值。 其余(可变数量的)参数代表可变数量的参数。 此函数必须 return 位置索引处的参数。 例如,如果函数被调用为
`find_item(1, -1, "hello", 'Z', 10.03)`
必须return"hello"
如果调用为
find_item(2, -1, "hello", 'Z', 10.03)
必须return'Z'
如果调用为
find_item(3, -1, "hello", 'Z', 10.03, 'Q', 100)
它必须 return 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 ; ;
}
这段代码编译不通过,因为return类型不统一,无法推导。 我想知道是否有任何方法可以实现这一目标。或者它是一个无效的用例。 如果能做到,那怎么做。
这不是 C++ 惯用的处理方式,但您可以使用 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)) ;
}
由于您的 return 类型由 运行 时间变量 inx
决定,因此无法知道 find_item
的确切 return 类型在编译时。
你需要做的是键入擦除。可以returnstd::variant<Args...>
,根据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]);
}
另一种类型擦除的方法是使用函数指针:
#include <variant>
#include <array>
#include <tuple>
template<class... Args>
constexpr auto find_item(std::size_t index, Args... args) {
constexpr auto funcs = []<std::size_t... Is>(std::index_sequence<Is...>) {
return std::array{ +[](Args... args) {
return std::variant<Args...>(
std::in_place_index<Is>, std::get<Is>(std::tuple(args...)));
}... };
}(std::index_sequence_for<Args...>{});
return funcs[index](args...);
}
I want to know if there is any way that this can be achieved.
没有
在 C/C++(静态类型语言)中,从函数 编辑的类型 return 必须 取决于 参数的类型,而不是值。
所以类型 return 来自以下调用
find_item(1, -1, "hello", 'Z', 10.03);
find_item(2, -1, "hello", 'Z', 10.03);
find_item(3, -1, "hello", 'Z', 10.03);
必须相同。
点。
您可以绕过此规则 return使用 std::variant
(可以包含不同类型的值)或 std::any
(可以包含通用值),但是独立于接收值确定的类型。
如果您将 type/value 的索引(在您的情况下是第一个参数)作为模板参数传递,则不同。
我的意思是:如果你按如下方式调用 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>()
可以return一个char const *
,find_item<2>()
可以return一个char
和find_item<3>()
可以return一个double
.
这是因为find_item<1>()
、find_item<2>()
和find_item<3>()
是不同的函数,所以可以有不同的return类型。
但是...这样...我们几乎获得了从 std::tuple
.
std::get<>()
不幸的是,只有当索引(模板参数)在编译时已知时,您才能使用此解决方案。
换句话说,你不能做出如下的东西
for ( auto i = 1 ; i < 4 ; ++i )
{ // .............NO! ---V
auto value = find_item<i>(-1, "hello", 'Z', 10.03);
}