我写了一个模板,它接受一个istream&和一个函数,应该从 中提取这个函数的所有参数,istream用这些参数调用函数并返回结果。一切正常,除了函数参数的评估顺序。请参阅下面的代码、更多详细信息和最终问题:
#include <iostream>
#include <vector>
void Foo(int i, std::string s)
{
std::cout << "input was " << i << " and " << s << '\n';
}
template<typename T>
T Parse(std::istream &s)
{
T res;
s >> res;
return res;
}
template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
return f(Parse<TArgs>(s)...);
}
int main()
{
Bar(std::cin, Foo);
}
Run Code Online (Sandbox Code Playgroud)
输入:
1 2
Run Code Online (Sandbox Code Playgroud)
预期输出:
input was 1 and 2
Run Code Online (Sandbox Code Playgroud)
实际输出:
input was 2 …Run Code Online (Sandbox Code Playgroud) 一个 C++ 函数可以有多个参数包。虽然看起来不太实用,但了解它们的语言规则仍然很有趣。
例如,如果有两个重载:
constexpr int f(auto...) { return 1; }
constexpr int f(auto..., auto...) { return 2; }
Run Code Online (Sandbox Code Playgroud)
f不带参数的调用f()在 MSVC 中选择版本 1,在 Clang 中选择版本 2,ambiguous overloaded call在 GCC 中选择版本 2。
如果f使用参数调用f(1),则 MSVC 和 GCC 都选择版本 1,而 Clang 仍选择版本 2。
演示: https: //gcc.godbolt.org/z/PWr6h1dn1
这里是哪个编译器?
有一个类似的问题带有两个参数包的函数模板重载解析,但是
c++ language-lawyer overload-resolution c++20 parameter-pack
我无法理解如何在 C++ 中转发参数包的元素。请以下面的代码为例:
#include <iostream>
void print(const int& value) {
std::cout << "print(const int& value) - " << value << std::endl;
}
void print(int&& value) {
std::cout << "print(int&& value) - " << value << std::endl;
}
template <class... Arg>
void print_each_argument(Arg&&... args) {
for(auto&& a: { args... }) {
print(std::forward<decltype(a)>(a));
}
}
int main() {
int some_value = 10;
int other_value = 20;
print_each_argument(some_value, other_value, 12, 14);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
print(const int& value) - 10
print(const int& value) …Run Code Online (Sandbox Code Playgroud) c++ variadic-templates perfect-forwarding c++20 parameter-pack
我试图在编译时确定所有传递对象的大小,然后在超过最大大小时通过 static_assert 中止构建过程。
#include <iostream>
template<class T>
class Test
{
public:
T value;
constexpr size_t size() const { return sizeof(T) + 3; }
};
template<typename ...T>
constexpr int calc(const T&...args)
{
return (args.size() + ...);
}
template<typename ...T>
void wrapper(const T& ...args)
{
// error: 'args#0' is not a constant expression
constexpr int v = calc(args...);
static_assert(v <= 11, "oops");
}
int main()
{
Test<int> a;
Test<char> b;
// a.size() + b.size() == 11
// works
constexpr int v = …Run Code Online (Sandbox Code Playgroud) 假设我有一个sum带有可变参数包的函数。
该函数需要使用运算符 ADD UP 参数包中的所有参数+。
注意:它不能以任何方式使用运算符+=,并且只能使用运算符+(因为程序不能假设所有参数都已operator+=重载)。
然后,函数sum需要返回整个“总和”或累加。
这是它的基本结构:
template <class... Args>
auto sum(Args... args)
{
// ... The code
}
Run Code Online (Sandbox Code Playgroud)
注意:所有参数可能不是同一类型,并且您可以假设operator+参数包的所有类型都存在相应的重载。
了解我正在使用 C++ 20 可能会有所帮助。
包索引是在 C++26 中引入的,我希望此功能能够对元编程产生重大影响,特别是对于索引包,否则需要解决方法。
由于包索引说明符的语法是:
typedef-name ... [ expression ]
Run Code Online (Sandbox Code Playgroud)
typedef-name是identifier或simple-template-id有了上述信息,是否允许:
template <typename>
using apply_t = bool;
// #1
template <typename... Args>
using A = apply_t<Args>...[0];
// can be reworked with: apply_t<Args...[0]>
// #2
template <template <typename...> typename... Temps>
using B = Temps<>...[0]
// no other way other than this because 'Temps...[0]<>' is not allowed yet (?)
Run Code Online (Sandbox Code Playgroud) std::type_identity可用于提供不可推论的上下文。所以,我想知道它是否适用于推导的可变参数列表。但不同的编译器给出不同的结果。
https://godbolt.org/z/4cfqbxdeo
#include <type_traits>
struct in_between{};
template <typename... T>
struct args_tag
{
using type = std::common_type_t<T...>;
};
template <typename... T>
void bar(args_tag<T...>, std::type_identity_t<T>..., int, std::type_identity_t<T>...) {}
template <typename... T>
void bar(args_tag<T...>, std::type_identity_t<T>..., in_between, std::type_identity_t<T>...) {}
// example
int main() {
bar(args_tag<int, int>{}, 4, 8, 15, 16, 23);
bar(args_tag<int, int>{}, 4, 8, in_between{}, 16, 23);
}
Run Code Online (Sandbox Code Playgroud)
第一个使用 gcc 和 msvc 编译。
bar(args_tag<int, int>{}, 4, 8, 15, 16, 23);
Run Code Online (Sandbox Code Playgroud)
第二个只能用 msvc 编译。
bar(args_tag<int, int>{}, 4, 8, in_between{}, 16, 23);
Run Code Online (Sandbox Code Playgroud)
根据标准,行为应该是什么?
如何获取参数包的前n个元素?或者最后 n 个元素,或者 [n, n+1, ..., m) 中的一片元素?例如:
head<3>(1, 2.0f, "three", '4') => make_tuple(1, 2.0f, "three")
tail<2>(1, 2.0f, "three", '4') => make_tuple("three", '4')
slice<1,3>(1, 2.0f, "three", '4') => make_tuple(2.0, "three")
Run Code Online (Sandbox Code Playgroud)
这可以通过 std::tuple、std::integer_sequence 和 std::get 的组合来实现,但我想知道是否有更简单的方法。
我只是打印出一个非类型模板参数包。但如果我想在元素之间留有空格,我找不到有效的扩展。
例子:
template < int ... N >
struct X
{
static void Check() {
// this will become std::cout << ( 1 << 2 ) << std::endl; -> prints "4"
std::cout << "X" << (N << ...) << std::endl;
// this will become: ((std::cout << 1 ) << 2 ) << std::endl; -> prints "12"
(std::cout << ... << N) << std::endl;
// this becomes: (( std::cout << " " << 1 ) << 2 ) -> prints " …Run Code Online (Sandbox Code Playgroud) sizeof...当参数没有括号时,g++ 和 clang++ 都拒绝使用。例如,以下代码被拒绝:
template<typename... T> auto packsize = sizeof...T;
Run Code Online (Sandbox Code Playgroud)
$ g++ -std=c++20 -ggdb -O -Wall -Werror -c -o z.o z.cc
z.cc:1:50: error: 'sizeof...' argument must be surrounded by parentheses [-fpermissive]
1 | template<typename... T> auto packsize = sizeof...T;
| ^
$ clang++ -std=c++20 -ggdb -O -Wall -Werror -c -o z.o z.cc
z.cc:1:50: error: missing parentheses around the size of parameter pack 'T'
template<typename... T> auto packsize = sizeof...T;
^
()
1 error generated.
Run Code Online (Sandbox Code Playgroud)
CPPreference.org似乎也需要括号括起来T。然而,这样的限制并没有出现在 C++20 …