在函数调用时从异构初始化列表构建元组
Build tuple from heterogeneous initializer list at function call
考虑以下函数
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" 的行可以工作? (保持那条线不变)。
我的猜测是简短的回答是否定的。
粗略地说,{ 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")});
无论如何,你为此牺牲了可读性,从我的角度来看,这是不值得的。
在 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")));
但没有什么可以让该行保持不变并保留函数模板。
考虑以下函数
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" 的行可以工作? (保持那条线不变)。
我的猜测是简短的回答是否定的。
粗略地说,{ 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")});
无论如何,你为此牺牲了可读性,从我的角度来看,这是不值得的。
在 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")));
但没有什么可以让该行保持不变并保留函数模板。