为什么std :: endl会生成这个神秘的错误消息?

时间:2014-06-24 03:29:17

标签: c++ c++11 compiler-errors iostream variadic-templates

如果我尝试编译以下代码,我会收到以下编译器错误(请参阅代码。)如果删除了std::endl,则编译时没有错误。

#include <iostream>
#include <sstream>
#include <utility>

namespace detail
{
    template <class T>
    void print(std::ostream& stream, const T& item)
    {
        stream << item;
    }

    template <class Head, class... Tail>
    void print(std::ostream& stream, const Head& head, Tail&&... tail)
    {
        detail::print(stream, head);
        detail::print(stream, std::forward<Tail>(tail)...);
    }
}

template <class... Args>
void print(std::ostream& stream, Args&&... args)
//note: candidate function not viable: requires 3 arguments, but 4 were provided
{
    std::stringstream ss;
    detail::print(ss, std::forward<Args>(args)...);
    stream << ss.rdbuf();
}

int main()
{
    print(std::cout, "The answer is ", 42, std::endl);
    //error: no matching function for call to 'print'
}

3 个答案:

答案 0 :(得分:10)

std::endl是一个功能模板。使用它时,必须由编译器明确指定或推导出其模板参数。

std::ostream有一个过载:

basic_ostream<charT,traits>& operator<<(
    basic_ostream<charT,traits>& (*pf) (basic_ostream<charT,traits>&) );

当我们使用

std::cout << std::endl;

编译器推断出std::endl使用的类型。由于您在调用print时无法依靠自动类型扣除,因此您必须明确指出要使用的std::endl版本。

以下内容应该有效:

print(std::cout, "The answer is ", 42, std::endl<char, std::char_traits<char>>);

更新

我使用以下精简代码来跟踪问题:

#include <iostream>

namespace detail
{
   template <class T>
      void print(std::ostream& stream, const T& item)
      {
         stream << item;
      }
}

int main()
{
    // detail::print(std::cout, std::endl);
    detail::print(std::cout, std::endl<char, std::char_traits<char>>);
}

答案 1 :(得分:5)

我认为这是因为如果传递函数模板,模板类型推导会失败。它无法推断出使用。{/ p>实例化endl的参数

请注意endl的定义是:

template <class charT, class traits> 
basic_ostream<charT,traits>& endl (basic_ostream<charT,traits>& os);

更简单的例子:

template<class U> void func(U &u) { }

template<class T>
void print(const T &item) { }

int main()
{
print(func);    // error: matching function for call to 'print(<unresolved overloaded function type>)'
}

您的错误消息是因为它尝试了各种方法来将您的函数调用与参数包匹配,但它们都没有工作。

答案 2 :(得分:1)

您可以通过自己定义一个简单的endlLive Demo)来避免此问题:

constexpr struct endl_ {
    friend std::ostream& operator << (std::ostream& os, const endl_&) {
        os << '\n'; // << std::flush;
        return os;
    }
} endl;

template <class... Args>
void print(std::ostream& stream, Args&&... args)
{
    std::stringstream ss;
    std::initializer_list<int>{0, (void(ss << std::forward<Args>(args)), 0)...};
    stream << ss.rdbuf();
}

int main()
{
    print(std::cout, "The answer is ", 42, endl);
    //error: no matching function for call to 'print'
    print(std::cout, "The answer is NOT ", 13, endl);
}