【问题标题】:Is there a way to fold an initializer list in C++17有没有办法在 C++17 中折叠初始化列表
【发布时间】:2019-08-29 00:20:33
【问题描述】:

与使用参数包相比,有没有办法进行初始化列表折叠?我的问题是我有一个重载的构造函数,我想根据我是否使用{} 来调用不同的构造函数。这似乎与初始化列表一起工作正常,当我使用{} 时,它设法隐藏我的另一个参数构造函数,而不是当我使用() 构造它时,但如果我使用不使用的参数包则失败隐藏我的另一个参数构造函数。

另外,我看到人们在他们的折叠表达式中附加了 void,当我提到 cppreference 时我无法理解,它似乎对我的程序也没有任何影响。

编辑: 根据要求,举例说明问题:

#include <iostream>
#define USE_PARAMETER_PACK false

template<typename T>
struct Mega
{
    int d;
    T* arr;
    Mega(int d) : d(d), arr(new T[d]) {}

    Mega(int d, T u) : d(d), arr(new T[d])
    {
        std::fill(arr, arr + d, static_cast<T>(u));
    }
#if USE_PARAMETER_PACK == true
    template<typename ...Ts>
    Mega(Ts&& ... vals) : d(sizeof...(Ts)), arr(new T[sizeof...(Ts)])
    {
        // fills the array with the arguments at compile time
        int i = 0;
        (void(arr[i++] = static_cast<T>(vals)), ...);
    }
#else
    template<typename U>
    Mega(const std::initializer_list<U>& list) : d(list.size()), arr(new T[d])
    {
        auto it = list.begin();
        //int i = 0;
        //((arr[i++] = (list)), ...);
        for (size_t i = 0; i < d; ++i, ++it)
            arr[i] = static_cast<T>(*it);
    }
#endif
};

template<typename T>
std::ostream& operator<<(std::ostream& os, const Mega<T>& m)
{
    for (size_t i = 0; i < m.d; ++i)
        os << m.arr[i] << "\t";
    return os;
}

int main()
{
    int* k;
    k = new int[2];
    k[0] = 2;
    k[1] = 3;
    Mega<int> l( k[0] );
    // hides 1 argument ctor through {} invocation if using initializer_list,
    // not so with parameter pack
    Mega<int> m({ k[0]}); 
    Mega<int> n(k[0], k[1]);
    // hides 2 argument ctor through {} invocation if using initializer list
    // not so with parameter pack
    Mega<int> o({ k[0], k[1] }); 
    std::cout << l << "\n";
    std::cout << m << "\n";
    std::cout << n << "\n";
    std::cout << o << "\n";

    return 0;
}

注意注释掉的部分,我希望能够做这样的事情,以便在编译时弄清楚已知大小参数列表的填写过程,而不是我使用 for 循环。 应该为第一个 cout 打印一些垃圾值,为第二个 cout 打印 2(至少在 MSVC2017 中是这样,不知道这种隐藏机制是否符合标准)。请注意,如果将define 设置为true,则可以使用参数包ctor,但即使使用{} 语法,它也无法隐藏一个参数ctor。

Edit2:为了最大的方便,进一步更新了代码,只需将 define 更改为 true 以查看参数包无法使用 {} 语法隐藏 1 和 2 参数构造函数,而初始化列表 ctor 设法隐藏。

链接: 使用初始化列表: http://coliru.stacked-crooked.com/a/7b876e1dfbb18d73 输出:

0   0   

2   

3   3   

2   3   

使用参数包: http://coliru.stacked-crooked.com/a/11042b2fc45b5259 输出:

0   0   

0   0   

3   3   

3   3   

【问题讨论】:

  • 如果您发布 minimal reproducible example,有人可能会帮助您。
  • “初始化列表折叠”是什么意思?
  • @Barry 能够像折叠参数包一样折叠初始化列表。
  • 折叠中的 void 术语是为了禁止调用用户定义的运算符重载(尤其是逗号运算符),因为函数的参数不能是 cv 限定的 void。对于大多数用户来说可能不是问题,但对于正确、安全的库代码来说是必要的。
  • 初始化列表有一个在运行时选择的大小;折叠它们是循环的问题,而不是模板处理器。 (我不能完全确定这是否不仅仅是问题标题的答案。)

标签: c++ c++17 initializer-list constantfolding


【解决方案1】:

因为initializer_list 的长度在编译时未知(特别是具有不同数量元素的不同调用站点调用相同的函数),这是不可能 对其进行任何constexpr 处理。 (相关的成员函数are constexpr,但你不能在函数参数上使用它们。)折叠表达式特别需要一个参数包,其大小始终是一个常量表达式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-10
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多