【问题标题】:C++ std::function parameters const referenceC++ std::function 参数 const 参考
【发布时间】:2021-07-12 17:08:16
【问题描述】:

我想写一个函数,它可以接收一个ostream、一个可迭代对象v和一个函数op。该函数应该对 v 中的每个元素调用 op,然后将结果发送到 ostream。所以我写了以下代码:

template<typename T,
        typename IN = decltype(*std::declval<T>().begin()),
        typename FT = function<ostream&(ostream&, const IN&)>
        >
void func(ostream& ss, const T& v,
              FT op = [](ostream& os, const IN&v)->ostream&{ return os << v; }) {
    for (const auto& i: v) {
        std::invoke(op, ss, i);
    }
}

int main() {
    vector<int> vec = {1, 2, 3, 4};
    func(cout, vec);
    return 0;
}

当我尝试使用 clang++ 编译这些代码时,出现以下错误。

 /mnt/d/codes/stlprinter/stack.cpp:42:9: error: no matching function for call to 'invoke'
        std::invoke(op, ss, i);
        ^~~~~~~~~~~
/mnt/d/codes/stlprinter/stack.cpp:48:5: note: in instantiation of function template specialization 'func<std::vector<int, std::allocator<int>>, int &, std::function<std::basic_ostream<char> &(std::basic_ostream<char> &, int &)>>' requested here
    func(cout, vec);
    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:85:5: note: candidate template ignored: substitution failure [with _Callable = std::function<std::basic_ostream<char> &(std::basic_ostream<char> &, int &)> &, _Args = <std::basic_ostream<char> &, const int &>]: no type named 'type' in 'std::invoke_result<std::function<std::basic_ostream<char> &(std::basic_ostream<char> &, int &)> &, std::basic_ostream<char> &, const int &>'
    invoke(_Callable&& __fn, _Args&&... __args)
    ^
1 error generated.

错误信息表明在调用invoke时,op的类型是_Callable = std::functionstd::basic_ostream &,但是op是由FT = function,为什么第二个参数的'const'说明符丢失了?

【问题讨论】:

    标签: c++ c++11 templates functional-programming


    【解决方案1】:

    注意IN,即decltype(*std::declval&lt;T&gt;().begin())类型是引用int&amp;;那么对于const IN&amp;const 在引用上是合格的,只是被忽略了。所以给定INint&amp;, const IN&amp; -> int&amp; &amp; -> int&amp;

    查看decltype的行为:

    1. ...
    2. 如果参数是 T 类型的任何其他表达式,并且
      a) ...
      b) 如果表达式的值类别是左值,则 decltype 产生 T&;
      c) ...

    您可以通过std::remove_referencestd::decay 删除参考部分。例如

    template<typename T,
            typename IN = std::remove_reference_t<decltype(*std::declval<T>().begin())>,
    //                    ^^^^^^^^^^^^^^^^^^^^^^^^                                    ^
            typename FT = function<ostream&(ostream&, const IN&)>
            >
    void func(ostream& ss, const T& v,
                  FT op = [](ostream& os, const IN&v)->ostream&{ return os << v; }) {
        for (const auto& i: v) {
            std::invoke(op, ss, i);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      • 2018-04-20
      • 2021-05-25
      • 2012-01-29
      • 2020-07-13
      • 1970-01-01
      相关资源
      最近更新 更多