简体   繁体   English

可变参数模板函数:没有匹配的函数,用于调用std :: endl

[英]Variadic Template Functions: No matching function for call, std::endl

In my code, I use variadic template functions for the logging purpose. 在我的代码中,我使用可变参数模板函数进行日志记录。 But when I use std::endl as parameter, I get the following compiler error: 但是当我使用std::endl作为参数时,我得到以下编译器错误:

Error: no matching function for call to 'LOG_ERROR(const char [14], int&, )' LOG_ERROR("Sum of x+y = ", z, std::endl); 错误:没有匹配函数来调用'LOG_ERROR(const char [14],int&,)'LOG_ERROR(“sum of x + y =”,z,std :: endl);

note: candidate: 'void LOG_ERROR()' inline void LOG_ERROR() { 注意:候选人:'void LOG_ERROR()'内联void LOG_ERROR(){

note: candidate expects 0 arguments, 3 provided 注意:候选人需要0个参数,3个提供

My Code: 我的代码:

#include <iostream>

inline void LOG_ERROR() { 
    std::cout << std::endl;
}

template<typename First, typename ...Rest>
void LOG_ERROR(First && first, Rest && ...rest){
    std::cout << std::forward<First>(first);
    LOG_ERROR(std::forward<Rest>(rest)...);
}

int main() {
    int foo=40;
    LOG_ERROR("My foo = ", foo, std::endl);
}

The code works fine with "\\n" but I would love to learn why it fails with std::endl and how I can fix it 代码与"\\n"一起工作正常,但我很想知道为什么它失败了std::endl以及我如何解决它

Long story short - std::endl is function template which template arguments can't be deduced while passing. std::endl短 - std::endl是函数模板,传递时不能推导出模板参数。 You can help Your compiler this way: 您可以这样帮助您的编译器:

LOG_ERROR("My foo = ", foo, std::endl<char, std::char_traits<char>>);

As much as I feel this is ugly piece of code it works perfectly. 尽管我觉得这是一段丑陋的代码,但它完美无缺。

Until someone comes with a better solution, you can use a trivial wrapper with an appropriate operator overload: 在有人提供更好的解决方案之前,您可以使用具有适当运算符重载的简单包装器:

struct EndlWrap {};

std::ostream& operator << (std::ostream& os, EndlWrap) {
   return os << std::endl;
}

which should be usable like this: 应该像这样使用:

LOG_ERROR("My foo = ", foo, EndlWrap{});

This has an advantage when your logging destination might be a non-standard stream, ie, the template arguments of std::endl can still be deduced when it's << 'd into the stream. 这有一个好处,当你的日志目标可能是非标准流,即,模板参数std::endl时,它仍然可以推断<<倒是到流。

std::endl is not a character type or any other type. std::endl不是字符类型或任何其他类型。 It is output stream manipulator. 它是输出流操纵器。 Its return type is output stream. 它的返回类型是输出流。

So, you can not pass it without typecasting. 所以,如果没有类型转换,你就无法通过它。 Please look here 请看这里

You can use defaulted template parameters and defaulted function arguments instead of a variadic template. 您可以使用默认模板参数和默认函数参数而不是可变参数模板。

The code is less clean and you will have to choose a limitation on the number of parameters, but it will do the job: 代码不太干净,您必须选择参数数量的限制,但它将完成工作:

template<class...>
inline void LOG_ERROR_();
template<>
inline void LOG_ERROR_<>() { 
    std::cout << std::endl;
}
template<typename First, typename ... Rest>
void LOG_ERROR_(First && first, Rest && ...rest){
    std::cout << std::forward<First>(first);
    LOG_ERROR_<Rest...>(std::forward<Rest>(rest)...);
    //could be cleaner with if constexpr
}

using manip_t = std::basic_ostream<char>&(*)(std::basic_ostream<char>&);

std::basic_ostream<char>& no_manip(std::basic_ostream<char>& o){
    return o;
}

template<typename A=manip_t
  ,typename B=manip_t, typename C= manip_t
  ,typename D=manip_t // to be continued
  >
inline void LOG_ERROR(A&& a=no_manip, B&& b=no_manip,C&& c=no_manip
              ,D&& d=no_manip /*to be continued*/){
    LOG_ERROR_<A,B,C,D/*to be continued*/>(
       std::forward<A>(a),std::forward<B>(b),std::forward<C>(c),
        std::forward<D>(d)/*to be continued*/);
}

Depending on the compiler this code could produce ugly assembly. 根据编译器,此代码可能会产生丑陋的程序集。 One solution is to write an overload for each possible number of argument, or have a good knowldge of compiler specific function attributes (always_inline,etc...) 一种解决方案是为每个可能的参数编写一个重载,或者具有编译器特定函数属性的良好知识(always_inline等...)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM