jjzjj

C++:将元组转换为类型 T

coder 2024-02-20 原文

我正在尝试创建一个名为 tuple_cnv 的类,它带有一个(隐式)转换运算符以从元组构造任何对象(如 C++17 std::make_from_tuple 函数),但具有递归性质,以这种方式,如果一个元组由其他元组组成,它会将任何“内元组”转换为 tuple_cnv 以允许递归就地构造目标类型:

#include <iostream>
#include <utility>
#include <tuple>
#include <functional>

struct A { int i1, i2, i3; };
struct B { A a1, a2; };

template<class T> struct tuple_cnv;

template<class... Ts>
struct tuple_cnv<std::tuple<Ts...> >
{
    using tuple_t = std::tuple<Ts...>;
    std::reference_wrapper<tuple_t const> ref;

    tuple_cnv(tuple_t const& t) : ref(t) {}

    template<class T>
    operator T() const 
    { return p_convert<T>(std::index_sequence_for<Ts...>{}); }

private:
    template<class T>
    static T const& p_convert(T const& t) { return t; }

    template<class... Tss>
    static tuple_cnv<Tss...> p_convert(std::tuple<Tss...> const& t)
    { return tuple_cnv<std::tuple<Tss...> >(t); }

    template<class T, std::size_t... I>
    T p_convert(std::index_sequence<I...>) const
    { return {p_convert(std::get<I>(ref.get()))...}; }
};

template<class T>
auto make_tuple_cnv(T const& t) { return tuple_cnv<T>(t); }

using tup = std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> >;

int main()
{
    tup t{{3, 4, 5}, {1, 7, 9}};

    // Equivalent to: B b{{3,4,5}, {1,7,9}};
    B b = make_tuple_cnv(t);

    std::cout << b.a2.i3 << std::endl;
}

如有疑问,行:

{p_convert(std::get<I>(ref.get()))...}

必须在其元素的逗号分隔列表中扩展元组(在 {...} 内以获得初始化列表),但用相应的 替换每个元组元素tuple_cnv 允许在构造对象 T 时通过每个内部 tuple_cnv 的(隐式)转换运算符创建初始化列表树。

请参阅 main 函数中注释的“预期等效”表达式。

问题是我遇到了一个编译器错误,错误太大以至于我无法理解我的实现有什么问题:

main.cpp: In instantiation of 'T tuple_cnv<std::tuple<_Tps ...> >::p_convert(std::index_sequence<I ...>) const [with T = B; long unsigned int ...I = {0, 1}; Ts = {std::tuple<int, int, int>, std::tuple<int, int, int>}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int, 0, 1>]':
main.cpp:28:26:   required from 'tuple_cnv<std::tuple<_Tps ...> >::operator T() const [with T = B; Ts = {std::tuple<int, int, int>, std::tuple<int, int, int>}]'
main.cpp:53:27:   required from here
main.cpp:40:51: error: could not convert '{tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::p_convert<std::tuple<int, int, int> >((* & std::get<0, std::tuple<int, int, int>, std::tuple<int, int, int> >((* &((const tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >*)this)->tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::ref.std::reference_wrapper<const std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::get())))), tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::p_convert<std::tuple<int, int, int> >((* & std::get<1, std::tuple<int, int, int>, std::tuple<int, int, int> >((* &((const tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >*)this)->tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::ref.std::reference_wrapper<const std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::get()))))}' from '<brace-enclosed initializer list>' to 'B'
     { return {p_convert(std::get<I>(ref.get()))...}; }
                                                   ^

那个编译器错误是关于什么的?什么是我没看到的?

注意:按照@Barry 的建议,我使用apply 更改了实现,而是调用了tuple_to_args,因为实现不是完全等效(std::apply 使用 std::invoke,它处理不同类型的函数,例如指向成员函数的指针):

template<class... Ts>
constexpr auto indexes(std::tuple<Ts...> const&)
{ return std::index_sequence_for<Ts...>{}; }

template<class fun_t, class tuple_t, std::size_t... I>
decltype(auto) tuple_to_args(fun_t&& f, tuple_t&& tuple, std::index_sequence<I...> const&)
{ return f(std::get<I>(std::forward<tuple_t>(tuple))...); }

template<class fun_t, class tuple_t>
decltype(auto) tuple_to_args(fun_t&& f, tuple_t&& t)
{ return tuple_to_args(std::forward<fun_t>(f), std::forward<tuple_t>(t), indexes(t)); }

并且使用tuple_to_args作为辅助函数,转换运算符的实现变为:

template<class T>
operator T() const 
{
    auto inner_f = [](auto&&... tuple) -> T {
        return {p_convert(std::forward<decltype(tuple)>(tuple))...};
    };

    return tuple_to_args(inner_f, ref.get());
}

非静态的 p_convert 函数也被删除了,但编译器错误仍然非常相似:

main.cpp: In instantiation of 'tuple_cnv<std::tuple<_Tps ...> >::operator T() const::<lambda(auto:1&& ...)> [with auto:1 = {const std::tuple<int, int, int>&, const std::tuple<int, int, int>&}; T = B; Ts = {std::tuple<int, int, int>, std::tuple<int, int, int>}]':
main.cpp:15:11:   required from 'decltype(auto) tuple_to_args(fun_t&&, tuple_t&&, std::index_sequence<I ...>&) [with fun_t = tuple_cnv<std::tuple<_Tps ...> >::operator T() const [with T = B; Ts = {std::tuple<int, int, int>, std::tuple<int, int, int>}]::<lambda(auto:1&& ...)>&; tuple_t = const std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> >&; long unsigned int ...I = {0, 1}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int, 0, 1>]'
main.cpp:19:23:   required from 'decltype(auto) tuple_to_args(fun_t&&, tuple_t&&) [with fun_t = tuple_cnv<std::tuple<_Tps ...> >::operator T() const [with T = B; Ts = {std::tuple<int, int, int>, std::tuple<int, int, int>}]::<lambda(auto:1&& ...)>&; tuple_t = const std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> >&]'
main.cpp:38:29:   required from 'tuple_cnv<std::tuple<_Tps ...> >::operator T() const [with T = B; Ts = {std::tuple<int, int, int>, std::tuple<int, int, int>}]'
main.cpp:60:27:   required from here
main.cpp:35:71: error: could not convert '{tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::p_convert<std::tuple<int, int, int> >((* & std::forward<const std::tuple<int, int, int>&>((* & tuple#0)))), tuple_cnv<std::tuple<std::tuple<int, int, int>, std::tuple<int, int, int> > >::p_convert<std::tuple<int, int, int> >((* & std::forward<const std::tuple<int, int, int>&>((* & tuple#1))))}' from '<brace-enclosed initializer list>' to 'B'
             return {p_convert(std::forward<decltype(tuple)>(tuple))...};

最佳答案

问题出在这里:

template<class... Tss>
static tuple_cnv<Tss...> p_convert(std::tuple<Tss...> const& t)
{ return tuple_cnv<std::tuple<Tss...> >(t); }

你尽可能地难以发现其中的错误。你有两个名称相同但做不同事情的函数(p_convert() 给你一个 T和处理递归的 p_convert())。这令人困惑。

相反,执行 apply (因为你在 C++14 上)。然后使用apply:

template <class T>
operator T() const {
    return std::apply([](auto const&... elems) -> T {
        return {p_convert(elems)...};
    }, ref);
}

关于C++:将元组转换为类型 T,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46184585/

有关C++:将元组转换为类型 T的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  4. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  7. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  8. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  9. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  10. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

随机推荐