在函数调用时从异构初始化列表构建元组

Posted

技术标签:

【中文标题】在函数调用时从异构初始化列表构建元组【英文标题】:Build tuple from heterogeneous initializer list at function call 【发布时间】:2017-11-05 19:18:01 【问题描述】:

考虑以下函数

template <class... T, class... U>
void f(std::tuple<T...> t, std::tuple<U...> u)

    std::cout << sizeof...(T) << " " << sizeof...(U) << std::endl;


int main(int argc, char* argv[]) 

    f(3, 3.5, "Hello World!", 'a', std::string("b")); // Fails
    return 0;

在 C++17 中是否有任何方法可以修改函数签名,以便标记为“失败”的行可以工作? (保持那条线不变)。

【问题讨论】:

【参考方案1】:

我的猜测是 简短的回答是否定的。 粗略地说, args... 不是元组,您会遇到与 C++14 中相同的推导和转换问题。


话虽如此,在 C++14/17 中,您可以这样做来模拟它(最小的工作示例):

#include<iostream>
#include<string>
#include<tuple>
#include<utility>

template <class... T, class... U>
void f_(std::tuple<T...> t, std::tuple<U...> u) 
    std::cout << sizeof...(T) << " " << sizeof...(U) << std::endl;


template<typename... T>
auto f(T... t) 
    return [tupstd::make_tuple(t...)](auto... u) 
        f_(std::move(tup), std::make_tuple(u...));
    ;


int main(int argc, char* argv[]) 
    f(3, 3.5, "Hello World!")('a', std::string("b"));
    return 0;

通用 lambda 可以为您带来魔力,并且您可以通过额外的间接级别获得与您想要的类似的东西(这通常有助于解决任何问题)。


在 C++17 中,您也可以这样做:

f(std::tuple3, 3.5, "Hello World!", std::tuple'a', std::string("b"));

这是直接从对构造函数的调用中推导出的参数类型,而不是显式指定它们。使用别名,您甚至可以更进一步,将调用点处的表达式简化为如下所示:

f(T3, 3.5, "Hello World!", T'a', std::string("b"));

无论如何,您为此牺牲了可读性,从我的角度来看,这不值得。

【讨论】:

【参考方案2】:

在 C++17 中,你可以这样写:

f(std::tuple3, 3.5, "Hello World!", std::tuple'a', std::string("b"));

之前,你可以使用std::make_tuple:

f(std::make_tuple(3, 3.5, "Hello World!"), std::make_tuple('a', std::string("b")));

但没有什么可以让该行保持不变并保留函数模板。

【讨论】:

以上是关于在函数调用时从异构初始化列表构建元组的主要内容,如果未能解决你的问题,请参考以下文章

Spark:从异构数据中写入 Paquet

ORA-00942: 从异构服务的表中选择某些内容时,表或视图不存在

继承中的构造析构函数调用顺序

Scala构建元数据

C++--继承中的构造与析构父子间的冲突

构造函数初始化列表来初始化字段析构函数拷贝构造函数