如何编写一个函数重载,它接受任意大小的元组并返回另一个相同大小的元组,其中int变为double(添加0.5值),char变为string,size_t变为int(变为相反的符号) ),以及我们可能想要的任何其他类型的改变。例如,函数foo
获取tuple<int, char, size_t>
并返回tuple<double, string, int>
,而tuple<size_t, char>
则返回tuple<int, string>
。
答案 0 :(得分:7)
这是一种方式:
步骤1 - 声明转换器的概念:
template<class From>
struct converter;
第2步 - 定义它的一些特化。这些拼写了转换规则。
template<> struct converter<int>
{
template<class Arg>
auto operator()(Arg&& arg) const {
return std::size_t(arg);
}
};
template<> struct converter<char>
{
template<class Arg>
auto operator()(Arg&& arg) const {
return std::string(1, arg);
}
};
template<> struct converter<std::size_t>
{
template<class Arg>
auto operator()(Arg&& arg) const {
using int_type = long long;
auto result = int_type(arg);
return -result;
}
};
步骤3 - 根据输入元组,输入元组中每个索引处的类型(输入元组和输入元组的转换)编写转换函数(这个有点讨厌):
template<class Tuple, std::size_t...Is>
auto convert_impl(Tuple&& t, std::index_sequence<Is...>)
{
using tuple_type = std::decay_t<Tuple>;
return std::make_tuple(converter<std::tuple_element_t<Is, tuple_type>>()(std::get<Is>(std::forward<Tuple>(t)))...);
}
第4步 - 提供易于使用的界面:
template<class Tuple>
auto convert(Tuple&& t)
{
using tuple_type = std::decay_t<Tuple>;
return convert_impl(std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<tuple_type>::value>());
}
第5步 - 写一个测试:
int main()
{
auto t = convert(std::make_tuple(int(1), char('a'), std::size_t(6)));
}
此解决方案还具有完美转发作为奖励。
答案 1 :(得分:1)
很抱歉,但以下解决方案不是c ++ 11,而是c ++ 14(可以针对c ++ 11进行修改,但并不是一件容易的事)
首先,你需要一个模板函数来(不)转换泛型值(你不想修改的那些)
template <typename T>
T conv (T const & t)
{ return t; }
接下来,您需要进行转换
double conv (int const & i)
{ return i + 0.5; }
std::string conv (char const & c)
{ return { c }; }
int conv (std::size_t const & s)
{ return -s ; }
此时(使用辅助函数接收元组类型的索引列表),使用c ++ 14返回auto
类型工具,它非常简单
template <typename ... Ts, std::size_t ... Is>
auto convTH (std::tuple<Ts...> const & t,
std::index_sequence<Is...> const &)
{ return std::make_tuple( conv(std::get<Is>(t))... ); }
template <typename ... Ts>
auto convT (std::tuple<Ts...> const & t)
{ return convTH(t, std::make_index_sequence<sizeof...(Ts)>{}); }
以下是一个完整的工作示例
#include <tuple>
#include <utility>
#include <iostream>
template <typename T>
T conv (T const & t)
{ return t; }
double conv (int const & i)
{ return i + 0.5; }
std::string conv (char const & c)
{ return { c }; }
int conv (std::size_t const & s)
{ return -s ; }
template <typename ... Ts, std::size_t ... Is>
auto convTH (std::tuple<Ts...> const & t,
std::index_sequence<Is...> const &)
{ return std::make_tuple( conv(std::get<Is>(t))... ); }
template <typename ... Ts>
auto convT (std::tuple<Ts...> const & t)
{ return convTH(t, std::make_index_sequence<sizeof...(Ts)>{}); }
int main ()
{
std::tuple<long, int, char, std::size_t, unsigned long long>
t0 = { 0L, 1, '2', 3U, 4ULL };
auto t1 = convT(t0);
static_assert( std::is_same<decltype(t1),
std::tuple<long, double, std::string, int, unsigned long long>>{}, "!");
std::cout << "0) " << std::get<0U>(t1) << std::endl;
std::cout << "1) " << std::get<1U>(t1) << std::endl;
std::cout << "2) " << std::get<2U>(t1) << std::endl;
std::cout << "3) " << std::get<3U>(t1) << std::endl;
std::cout << "4) " << std::get<4U>(t1) << std::endl;
}
答案 2 :(得分:0)
这里是返回类型的C ++ 11解决方案,因此无需使用auto
:
#include <iostream>
#include <type_traits>
#include <utility>
#include <string>
#include <tuple>
template <typename T, typename Map> struct FindCounterpartType;
template <typename T, template <typename...> class M, template <typename, typename> class P, typename U, typename... Pairs>
struct FindCounterpartType<T, M<P<T,U>, Pairs...>> {
using type = U;
};
template <typename T, template <typename...> class M, typename Pair, typename... Pairs>
struct FindCounterpartType<T, M<Pair, Pairs...>> : FindCounterpartType<T, M<Pairs...>> {};
template <typename Pack, typename Map, typename Output> struct ChangeTypesHelper;
template <template <typename...> class P, typename... Output, typename Map>
struct ChangeTypesHelper<P<>, std::tuple<Output...>, Map> {
using type = P<Output...>;
};
template <template <typename...> class P, typename First, typename... Rest, typename... Output, typename Map>
struct ChangeTypesHelper<P<First, Rest...>, std::tuple<Output...>, Map> : ChangeTypesHelper<P<Rest...>, std::tuple<Output..., typename FindCounterpartType<First, Map>::type>, Map> {};
template <typename Pack, typename Map>
struct ChangeTypes : ChangeTypesHelper<Pack, std::tuple<>, Map> {};
// Testing
template <typename...> struct M;
template <typename...> struct Pack;
template <typename, typename> struct P;
using Map = M< P<int, std::string>, P<char, std::size_t>, P<double, bool> >;
int main() {
std::cout << std::boolalpha << std::is_same<
ChangeTypes<std::tuple<int, char, double>, Map>::type,
std::tuple<std::string, std::size_t, bool>
>::value << '\n';
std::cout << std::is_same<
ChangeTypes<Pack<char, double, double, int, int, int, char>, Map>::type,
Pack<std::size_t, bool, bool, std::string, std::string, std::string, std::size_t>
>::value << '\n';
std::cin.get();
}