标签: parameter-pack

参数包扩展中的求值顺序问题

我写了一个模板,它接受一个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++ pack-expansion parameter-pack

21
推荐指数
1
解决办法
504
查看次数

C++ 中具有多个参数包的函数的重载解析

一个 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

15
推荐指数
1
解决办法
333
查看次数

如何在C++中完美转发函数参数包的元素

我无法理解如何在 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

7
推荐指数
1
解决办法
262
查看次数

在 constexpr 中传递参数包

我试图在编译时确定所有传递对象的大小,然后在超过最大大小时通过 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)

c++ constexpr c++17 parameter-pack

6
推荐指数
1
解决办法
163
查看次数

返回可变参数包的添加

假设我有一个sum带有可变参数包的函数。
该函数需要使用运算符 ADD UP 参数包中的所有参数+

注意:它不能以任何方式使用运算符+=,并且只能使用运算符+(因为程序不能假设所有参数都已operator+=重载)。

然后,函数sum需要返回整个“总和”或累加。

这是它的基本结构:

template <class... Args>
auto sum(Args... args)
{
    // ... The code
}
Run Code Online (Sandbox Code Playgroud)

注意:所有参数可能不是同一类型,并且您可以假设operator+参数包的所有类型都存在相应的重载。

了解我正在使用 C++ 20 可能会有所帮助。

c++ sum variadic-templates parameter-pack

6
推荐指数
1
解决办法
114
查看次数

C++26 中是否允许 TemplatePack&lt;&gt;...[I]

包索引是在 C++26 中引入的,我希望此功能能够对元编程产生重大影响,特别是对于索引包,否则需要解决方法。

由于包索引说明符的语法是:

typedef-name ... [ expression ] 
Run Code Online (Sandbox Code Playgroud)
  • 其中typedef-nameidentifiersimple-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)

c++ parameter-pack c++26

6
推荐指数
1
解决办法
100
查看次数

std::type_identity 支持多个可变参数列表

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)

根据标准,行为应该是什么?

c++ templates language-lawyer c++20 parameter-pack

6
推荐指数
1
解决办法
251
查看次数

C++:获取参数包的头和尾

如何获取参数包的前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 的组合来实现,但我想知道是否有更简单的方法。

c++ templates variadic parameter-pack

5
推荐指数
1
解决办法
901
查看次数

非类型模板参数包扩展

我只是打印出一个非类型模板参数包。但如果我想在元素之间留有空格,我找不到有效的扩展。

例子:


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)

c++ fold-expression c++17 parameter-pack

5
推荐指数
1
解决办法
466
查看次数

C++20哪里禁止sizeof...T(不带括号)

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 …

c++ language-lawyer variadic-templates c++20 parameter-pack

5
推荐指数
1
解决办法
197
查看次数