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

17
考虑以下函数:
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中,是否有一种方法可以修改函数签名,使标记为“Fails”的行起作用?(保留该行不变)。

2个回答

12
我猜短答案是否定的。
粗略地说,{ 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 [tup{std::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::tuple{3, 3.5, "Hello World!"}, std::tuple{'a', std::string("b")});

这是直接从调用构造函数推断参数类型,而不是显式指定它们。使用别名甚至可以进一步减少调用点处的表达式,如下所示:

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

无论如何,从我的角度来看,为此你会牺牲可读性,这是毫无价值的。


7
在C++17中,您可能会编写以下代码:
f(std::tuple{3, 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")));

但不能让该行未修改,同时保留函数模板。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接