【问题标题】:How to pass in a brace-enclosed initializer list to a function?如何将大括号括起来的初始值设定项列表传递给函数?
【发布时间】:2020-12-04 00:04:00
【问题描述】:

我想编写一个函数,该函数可以与一个参数一起使用,否则该参数可能会直接出现在基于范围的循环中:

template <typename Iterable>
void sayIt(const Iterable& stuff) {
    for (const auto& e : stuff) {
        cout << e << endl;
    }
}

这适用于 stl 容器和其他类型,但不适用于大括号封闭的初始化程序:

std::vector<std::string> baz(2, "sorry");
sayIt(baz);              // okay
sayIt({"foo", "bar"});   // not okay

有没有办法让函数同时工作?

【问题讨论】:

    标签: c++ templates stl list-initialization range-based-loop


    【解决方案1】:

    Braced-init-list 没有类型并导致 template argument deduction 失败。

    非推断上下文

    在以下情况下,用于构成 P 的类型、模板和非类型值不参与模板参数推导,而是使用在其他地方推导或显式指定的模板参数。如果模板参数仅在非推导上下文中使用且未显式指定,则模板参数推导失败。

    1. 参数 P,其 A 是一个花括号初始化列表,但 P 不是 std::initializer_list,对一个的引用(可能是 cv-qualified)或对数组的引用:

    您可以将模板参数显式指定为std::initializer_list 以绕过推导,

    sayIt<std::initializer_list<std::string>>({"foo", "bar"});
    

    或者添加另一个使用std::initializer_list的重载。

    template <typename T>
    void sayIt(std::initializer_list<T> stuff) {
        sayIt<decltype(stuff)>(stuff);
    }
    

    【讨论】:

    • 如果我要写auto init = { "foo", "bar" }; 然后sayIt(init); 它会工作。编译器将init 推导出为std::initializer_list&lt;const char*&gt; 类型。但是{ "foo", "bar" } 的作用不是一样吗?为什么?
    • @jignatius 因为auto type deduction 有特殊规则。使用复制列表初始化,init 将被推导出为std::initializer_list
    猜你喜欢
    • 2011-05-31
    • 2021-11-21
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 2012-11-21
    相关资源
    最近更新 更多