Vin*_*ent 17 c++ tuples initialization aggregate-initialization c++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;
}
Run Code Online (Sandbox Code Playgroud)
在C++ 17中是否有任何方法可以修改函数签名,以便标记为"Fails"的行可以工作?(保持该线相同).
sky*_*ack 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;
}
Run Code Online (Sandbox Code Playgroud)
通用lambdas为你做了魔法,你有一些类似于你想要的东西与额外的间接水平(这通常有助于解决任何问题).
在C++ 17中,您也可以这样做:
f(std::tuple{3, 3.5, "Hello World!"}, std::tuple{'a', std::string("b")});
Run Code Online (Sandbox Code Playgroud)
这就是直接从对构造函数的调用推断出的参数类型,而不是显式指定它们.使用别名,您甚至可以进一步将调用点处的表达式减少为:
f(T{3, 3.5, "Hello World!"}, T{'a', std::string("b")});
Run Code Online (Sandbox Code Playgroud)
无论如何,你为此牺牲了可读性,从我的角度来看它是不值得的.
在C++ 17中,您可能会写:
f(std::tuple{3, 3.5, "Hello World!"}, std::tuple{'a', std::string("b")});
Run Code Online (Sandbox Code Playgroud)
之前,您可以使用std::make_tuple:
f(std::make_tuple(3, 3.5, "Hello World!"), std::make_tuple('a', std::string("b")));
Run Code Online (Sandbox Code Playgroud)
但没有什么可以保持线未经修改并保留功能模板.