[英]Can class type be deduced from pointer to member function template parameter
[英]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.