首页 文章

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

提问于
浏览
7

在我的代码中,我使用 variadic template functions 进行日志记录 . 但是当我使用 std::endl 作为参数时,我得到以下编译器错误:

错误:没有匹配函数来调用'LOG_ERROR(const char [14],int&,)'LOG_ERROR(“sum of x y =”,z,std :: endl);注意:候选:'void LOG_ERROR()'内联void LOG_ERROR(){注意:候选者需要0个参数,3个提供

我的代码:

#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);
}

代码与 "\n" 工作正常,但我很想知道为什么它失败 std::endl 以及如何解决它

4 回答

  • 8

    std::endl 不是字符类型或任何其他类型 . 它是输出流操纵器 . 它的返回类型是输出流 .

    所以,如果没有类型转换,你就无法通过它 . 请看here

  • 1

    长话短说 - std::endl 是函数模板,传递时不能推导出模板参数 . 您可以这样帮助您的编译器:

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

    尽管我觉得这是一段丑陋的代码,但它完美无缺 .

  • 1

    在有人提供更好的解决方案之前,您可以使用具有适当运算符重载的普通包装器:

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

    这应该是这样的:

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

    当您的日志记录目标可能是非标准流时,这有一个优势,即 std::endl 的模板参数在进入流时仍然可以推导出来 .

  • 7

    您可以使用默认模板参数和默认函数参数而不是可变参数模板 .

    代码不太干净,您必须选择参数数量的限制,但它将完成工作:

    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*/);
    }
    

    根据编译器,此代码可能会产生丑陋的程序集 . 一种解决方案是为每个可能的参数编写一个重载,或者具有编译器特定函数属性的良好知识(always_inline等...)

相关问题